设计模式深度解析:单例、工厂、适配器与代理模式

目录

[一、单例模式(Singleton Pattern)](#一、单例模式(Singleton Pattern))

原理

使用场景

优缺点

优点:

缺点:

实现代码

基础实现(非线程安全)

线程安全实现(加锁)

Java枚举实现(最佳实践)

[二、工厂模式(Factory Pattern)](#二、工厂模式(Factory Pattern))

原理

使用场景

优缺点

优点:

缺点:

实现代码

简单工厂

工厂方法

抽象工厂

[三、适配器模式(Adapter Pattern)](#三、适配器模式(Adapter Pattern))

原理

使用场景

优缺点

优点:

缺点:

实现代码

类适配器(继承)

对象适配器(组合)

实际应用示例(电压适配器)

[四、代理模式(Proxy Pattern)](#四、代理模式(Proxy Pattern))

原理

使用场景

优缺点

优点:

缺点:

实现代码

静态代理

动态代理(JDK)

Cglib代理


设计模式是软件开发中解决常见问题的可复用方案。本文将深入探讨四种常用的设计模式:单例模式、工厂模式、适配器模式和代理模式,分析它们的原理、使用场景、优缺点,并提供实现代码示例。

一、单例模式(Singleton Pattern)

原理

单例模式确保一个类只有一个实例,并提供一个全局访问点。它通过私有化构造函数、提供静态获取实例方法来实现。

使用场景

  • 需要控制资源访问,如数据库连接池

  • 全局配置对象

  • 日志记录器

  • 设备驱动程序

优缺点

优点:

  • 严格控制实例数量

  • 全局访问方便

  • 避免频繁创建销毁对象

缺点:

  • 违反单一职责原则(既管理生命周期又处理业务)

  • 难以扩展

  • 多线程环境下需要特殊处理

实现代码

基础实现(非线程安全)

java 复制代码
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

线程安全实现(加锁)

java 复制代码
public class ThreadSafeSingleton {
    // 必须使用 volatile 禁止指令重排序,保证可见性
    private static volatile ThreadSafeSingleton instance;

    // 私有构造方法,防止外部通过 new 创建实例
    private ThreadSafeSingleton() {}

    public static ThreadSafeSingleton getInstance() {
        // 第一次检查:避免每次都进入同步块,提高性能
        if (instance == null) {
            synchronized (ThreadSafeSingleton.class) {
                // 第二次检查:确保只有一个线程能创建实例
                if (instance == null) {
                    instance = new ThreadSafeSingleton();
                }
            }
        }
        return instance;
    }
}

/**
 * 线程安全的单例模式(双重检查锁定 DCL,Double-Checked Locking)
 *
 * 为什么它是线程安全的?
 *
 * 1. 双重检查(Double-Check)
 *    第一次检查 instance == null 时未加锁,可以避免每次调用 getInstance() 都进入同步块,
 *    只有真正需要第一次初始化时才进入 synchronized,降低锁粒度,提高性能。
 *
 * 2. synchronized 块
 *    第二次检查 instance == null 时已经在同步块内部,保证同一时刻只有一个线程能执行
 *    `instance = new ThreadSafeSingleton();`,防止重复创建对象。
 *
 * 3. volatile 关键字
 *    修饰 instance 的 `volatile` 有两个关键作用:
 *
 *    a) 可见性:保证一个线程修改 instance 后,其他线程立即可见最新值。
 *
 *    b) 禁止指令重排序:防止 JVM/CPU 的指令重排序导致对象尚未完全构造完成就被其他线程看到。
 *       创建对象实际上分为三步:
 *       1. 分配内存
 *       2. 初始化对象(调用构造方法)
 *       3. 将引用指向刚分配的内存地址
 *       如果没有 volatile,2 和 3 可能被重排序,导致其他线程拿到一个"半初始化"的对象。
 *
 * 所以:通过双重检查 + synchronized 保证互斥性,通过 volatile 保证可见性和禁止重排序,
 * 从而确保在任何并发场景下都只有一个实例被创建,并且所有线程都能正确看到完全初始化的实例。
 */

第一次检查:避免已经创建好的实例每次调用都进锁,提升性能。

第二次检查:真正要创建时才进锁,防止多线程同时第一次创建,保证只 new 一次。

Java枚举实现(最佳实践)

java 复制代码
public enum EnumSingleton {
    // 唯一实例
    INSTANCE;

    // 可以有任何字段或方法
    private int counter = 0;

    public void doSomething() {
        counter++;
        System.out.println("counter = " + counter);
    }
}
/**
 *  天生线程安全
 *    枚举常量在类加载阶段由 JVM 保证只实例化一次,且是原子操作;
 *    不需要任何同步代码,也永远不存在并发问题。
 *
 */

二、工厂模式(Factory Pattern)

原理

工厂模式定义一个创建对象的接口,但让子类决定实例化哪个类。它将对象创建与使用分离。

使用场景

  • 系统需要独立于其产品的创建、组合和表示

  • 需要提供产品的类库,只暴露接口

  • 需要灵活扩展系统时

优缺点

优点:

  • 解耦对象创建与使用

  • 易于扩展新产品

  • 符合开闭原则

缺点:

  • 增加了系统复杂度

  • 需要引入额外类

实现代码

简单工厂

java 复制代码
// ====== 简单工厂 ======
// 简单工厂:把"创建对象"的逻辑集中在一个类里,根据传入的 type 返回不同的产品实现
public class SimpleFactory {
    // 根据字符串 type 创建对应的产品对象
    public Product createProduct(String type) {
        switch (type) {
            case "A":
                return new ConcreteProductA();
            case "B":
                return new ConcreteProductB();
            default:
                throw new IllegalArgumentException("Unknown product type");
        }
    }
}

// 产品接口
interface Product {}

// 具体产品 A
class ConcreteProductA implements Product {}

// 具体产品 B
class ConcreteProductB implements Product {}

工厂方法

java 复制代码
// ====== 工厂方法 ======
// 工厂方法:把"创建对象"推迟到子类实现,父类只定义流程骨架
public abstract class Factory {
    // 子类必须实现,决定真正创建哪种产品
    public abstract Product createProduct();
    
    // 模板方法:先创建产品再使用
    public void doSomething() {
        Product product = createProduct();
        // 使用product
    }
}

// 具体工厂 A:负责生产 ConcreteProductA
class ConcreteFactoryA extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂 B:负责生产 ConcreteProductB
class ConcreteFactoryB extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

抽象工厂

java 复制代码
// ====== 抽象工厂 ======
// 抽象工厂:一次性创建"一族"相关或依赖的产品(这里为 ProductA + ProductB)
public interface AbstractFactory {
    // 创建 ProductA 系列对象
    ProductA createProductA();
    // 创建 ProductB 系列对象
    ProductB createProductB();
}

// 具体工厂 1:生产 ProductA1 与 ProductB1
class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA1();
    }
    
    @Override
    public ProductB createProductB() {
        return new ProductB1();
    }
}

// 具体工厂 2:生产 ProductA2 与 ProductB2
class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA2();
    }
    
    @Override
    public ProductB createProductB() {
        return new ProductB2();
    }
}

三、适配器模式(Adapter Pattern)

原理

适配器模式将一个类的接口转换成客户期望的另一个接口,使原本不兼容的类可以一起工作。

使用场景

  • 需要使用现有类,但其接口不符合要求

  • 需要创建可复用的类,与不相关或不可预见的类协同工作

  • 需要使用几个子类,但子类化每个类不现实

优缺点

优点:

  • 使不兼容的接口协同工作

  • 提高类的复用性

  • 灵活、可扩展

缺点:

  • 过多使用会使系统混乱

  • 增加系统复杂度

实现代码

类适配器(继承)

java 复制代码
// 目标接口
interface Target {
    void request();
}

// 需要适配的类
class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee's specific request");
    }
}

// 适配器
class ClassAdapter extends Adaptee implements Target {
    @Override
    public void request() {
        specificRequest();
    }
}

对象适配器(组合)

java 复制代码
class ObjectAdapter implements Target {
    private Adaptee adaptee;
    
    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    
    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

实际应用示例(电压适配器)

java 复制代码
// 中国220V插座
class ChineseSocket {
    public void provide220V() {
        System.out.println("Providing 220V");
    }
}

// 美国110V设备接口
interface USDevice {
    void workOn110V();
}

// 适配器
class SocketAdapter implements USDevice {
    private ChineseSocket socket;
    
    public SocketAdapter(ChineseSocket socket) {
        this.socket = socket;
    }
    
    @Override
    public void workOn110V() {
        socket.provide220V();
        System.out.println("Converting 220V to 110V");
    }
}

四、代理模式(Proxy Pattern)

原理

代理模式为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。

使用场景

  • 远程代理(远程方法调用)

  • 虚拟代理(延迟加载大对象)

  • 保护代理(控制访问权限)

  • 智能引用(引用计数、懒加载等)

优缺点

优点:

  • 职责清晰

  • 高扩展性

  • 智能化

缺点:

  • 增加系统复杂度

  • 可能降低请求处理速度

实现代码

静态代理

java 复制代码
interface Image {
    void display();
}

class RealImage implements Image {
    private String filename;
    
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }
    
    private void loadFromDisk() {
        System.out.println("Loading " + filename);
    }
    
    @Override
    public void display() {
        System.out.println("Displaying " + filename);
    }
}

class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;
    
    public ProxyImage(String filename) {
        this.filename = filename;
    }
    
    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

动态代理(JDK)

java 复制代码
interface Subject {
    void request();
}

class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject handling request");
    }
}

class DynamicProxyHandler implements InvocationHandler {
    private Object target;
    
    public DynamicProxyHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method call");
        Object result = method.invoke(target, args);
        System.out.println("After method call");
        return result;
    }
}

// 使用
Subject realSubject = new RealSubject();
Subject proxy = (Subject) Proxy.newProxyInstance(
    Subject.class.getClassLoader(),
    new Class[]{Subject.class},
    new DynamicProxyHandler(realSubject)
);
proxy.request();

Cglib代理

java 复制代码
class RealService {
    public void doSomething() {
        System.out.println("RealService doing something");
    }
}

class CglibProxy implements MethodInterceptor {
    public Object getProxy(Class clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method call");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method call");
        return result;
    }
}

// 使用
RealService proxy = (RealService) new CglibProxy().getProxy(RealService.class);
proxy.doSomething();

五、对比

模式 目的 主要应用场景 关键特点
单例 控制实例数量 全局唯一对象 私有构造、静态实例
工厂 封装对象创建 复杂对象创建 创建与使用分离
适配器 接口转换 兼容旧系统 包装不兼容接口
代理 控制访问 访问控制、增强功能 间接访问、功能增强
相关推荐
沉淀粉条形变量1 天前
rust 单例模式
开发语言·单例模式·rust
橘子编程1 天前
GoF 23 种设计模式完整知识总结与使用教程
java·c语言·开发语言·python·设计模式
UrSpecial1 天前
设计模式:模板方法模式
设计模式·模板方法模式
Lyyaoo.1 天前
【JAVA基础面经】线程安全的单例模式
java·安全·单例模式
如来神掌十八式1 天前
设计模式之装饰器模式
java·设计模式
qqxhb2 天前
26|Agent 设计模式:ReAct、Plan-and-Solve 与反射
设计模式·react模式·plan-and-solve·reflection模式
hssfscv2 天前
软件设计师下午题六——Java的各种设计模式
java·算法·设计模式
yaaakaaang2 天前
六、适配器模式
java·适配器模式
zhaoshuzhaoshu2 天前
设计模式之创建型设计模式详细解析(含示例)
单例模式·设计模式·架构
梦游钓鱼2 天前
c++中单例模式(局部静态变量)
开发语言·c++·单例模式