# 设计模式

# 单例模式(Singleton Pattern)

单例模式是一种创建型设计模式,旨在确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式通常用于需要共享资源或控制对资源的访问的情况。

  • 饿汉加载

    在饿汉式单例模式中,实例在类加载时就被创建并初始化。因此,无需在 getInstance() 方法中进行延迟实例化。该实例在整个应用程序的生命周期中都是可用的。这种实现方式基于类加载机制的特性,天然线程安全,但可能会造成资源浪费,因为即使在某些情况下没有使用该实例,它仍然被创建。

    public class Singleton {
        private static final Singleton instance = new Singleton();
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            return instance;
        }
    }
    
  • 懒汉加载

    在懒汉加载模式中,getInstance() 方法是获取 Singleton 实例的静态方法。在该方法中,首先检查 instance 是否为 null,如果是,则创建一个新的 Singleton 实例;如果不是,则直接返回现有的实例,适用于单线程环境。在多线程环境下,需要考虑线程安全性。

    public class Singleton {
        private static Singleton instance;
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

# 工厂模式(Factory Pattern)

工厂模式是一种创建型设计模式,它将对象的创建逻辑封装在一个工厂类中,从而隐藏了具体对象的创建细节,并提供了统一的接口来创建对象。

主要参与工厂模式的角色有:

  1. 抽象产品(Abstract Product):定义了产品的接口,是具体产品类的共同父类或接口。
  2. 具体产品(Concrete Product):实现了抽象产品接口,是工厂所创建的对象。
  3. 抽象工厂(Abstract Factory):声明了创建产品的方法,是工厂方法的核心接口。
  4. 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体产品的实例。
javaCopy code// 抽象产品 - 图形接口
public interface Shape {
    void draw();
}

// 具体产品 - 圆形类
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle.");
    }
}

// 具体产品 - 正方形类
public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a square.");
    }
}

// 抽象工厂 - 图形工厂接口
public interface ShapeFactory {
    Shape createShape();
}

// 具体工厂 - 圆形工厂
public class CircleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }
}

// 具体工厂 - 正方形工厂
public class SquareFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Square();
    }
}

# 观察者模式(Observer Pattern)

观察者模式(Observer Pattern)是一种行为型设计模式,用于在对象之间建立一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖它的对象都能得到通知并自动更新。

观察者模式涉及以下几个核心角色:

  1. Subject(主题):也称为被观察者或可观察对象,它维护一系列观察者并通知它们状态的变化。主题可以添加、删除和通知观察者。
  2. Observer(观察者):观察者是接收主题通知的对象。当主题的状态发生变化时,观察者会根据需求进行相应的处理。
import java.util.ArrayList;
import java.util.List;

// Subject(主题)接口
interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

// ConcreteSubject(具体主题)类
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String state;

    public void setState(String state) {
        this.state = state;
        notifyObservers();
    }

    public String getState() {
        return state;
    }

    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

// Observer(观察者)接口
interface Observer {
    void update();
}

// ConcreteObserver(具体观察者)类
class ConcreteObserver implements Observer {
    private String name;
    private ConcreteSubject subject;

    public ConcreteObserver(String name, ConcreteSubject subject) {
        this.name = name;
        this.subject = subject;
    }

    @Override
    public void update() {
        String state = subject.getState();
        System.out.println("Observer " + name + " received state: " + state);
    }
}

// 示例使用
public class ObserverPatternExample {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        Observer observer1 = new ConcreteObserver("Observer1", subject);
        Observer observer2 = new ConcreteObserver("Observer2", subject);

        subject.attach(observer1);
        subject.attach(observer2);

        subject.setState("state 1");
        // 输出:
        // Observer Observer1 received state: state 1
        // Observer Observer2 received state: state 1

        subject.setState("state 2");
        // 输出:
        // Observer Observer1 received state: state 2
        // Observer Observer2 received state: state 2

        subject.detach(observer1);

        subject.setState("state 3");
        // 输出:
        // Observer Observer2 received state: state 3
    }
}

Subject 接口定义了添加、删除和通知观察者的方法。ConcreteSubject 类实现了 Subject 接口,并在状态发生变化时通知观察者。Observer 接口定义了观察者的 update() 方法,该方法在接收到通知时执行相应的操作。ConcreteObserver 类实现了 Observer 接口,并根据需要实现 update() 方法。

在示例中,我们创建了一个具体主题 ConcreteSubject,并创建了两个具体观察者 ConcreteObserver。首先,我们将观察者添加到主题中,并设置主题的状态。当主题的状态发生变化时,观察者会接收到通知并执行相应的操作。

观察者模式可以实现松耦合的对象间交互,使得主题和观察者之间的关系可以动态建立和解除。它可以广泛应用于事件处理、消息系统、用户界面开发等场景,以实现对象之间的实时通信和状态更新。

# 适配器模式(Adapter Pattern)

适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成另一个客户端所期望的接口。适配器模式允许不兼容的类能够一起工作,解决了接口不匹配的问题。

适配器模式涉及以下几个核心角色:

  1. 目标接口(Target Interface):定义客户端所期望的接口,适配器将目标接口转换为被适配者的接口。

  2. 被适配者(Adaptee):存在于系统中的类,其接口与目标接口不匹配。

  3. 适配器(Adapter):实现了目标接口,并持有一个被适配者的实例,在目标接口的方法中调用被适配者的方法来完成适配。

// 目标接口
interface Target {
    void request();
}

// 被适配者类
class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee's specificRequest() called");
    }
}

// 适配器类
class Adapter implements Target {
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

// 示例使用
public class AdapterPatternExample {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);

        target.request(); // 通过适配器调用被适配者的方法
    }
}

在上述示例中,我们有一个目标接口 Target,其中定义了客户端所期望的方法 request()。然后,我们有一个被适配者类 Adaptee,其中有一个不匹配的方法 specificRequest()。最后,我们创建了一个适配器类 Adapter,它实现了目标接口 Target,并持有一个被适配者的实例,在目标接口的方法中调用被适配者的方法。

在示例中,我们通过创建一个适配器对象 Adapter,将 Adaptee 转换为了目标接口 Target。通过调用目标接口的方法 request(),实际上是在调用被适配者的方法 specificRequest()

适配器模式的优点在于可以使不兼容的类协同工作,增强了代码的复用性和灵活性。它允许在不改变现有代码的情况下进行接口的适配,符合开闭原则。然而,适配器模式也有一些缺点,如可能增加代码复杂性,引入了额外的间接层等。

适配器模式适用于

以下场景:

  • 当需要将一个已经存在的类集成到另一个接口时。
  • 当需要重用某个类,但是其接口与系统要求的接口不匹配时。
  • 当需要创建一个可重用的类,该类与其他不相关的类或不可预见的类协同工作时。

通过适配器模式,可以有效地解决不同接口之间的兼容性问题,使得不同类能够协同工作,提高了代码的灵活性和可维护性。