java设计模式大全:从原则到实现

69 阅读28分钟

设计模式的七大原则

  1. 开闭原则
  2. 里氏替换原则
  3. 依赖倒置原则
  4. 单一职责原则
  5. 接口隔离原则
  6. 最少知识原则
  7. 合成复用原则

设计模式原则详解

1. 开闭原则(Open/Closed Principle, OCP)

开闭原则的核心思想是一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。也就是说,在软件需求变更时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码。

2. 里氏替换原则(Liskov Substitution Principle, LSP)

里氏替换原则要求所有引用基类的地方必须能透明地使用其子类的对象,而不会产生错误。这个原则确保了子类在应用程序中可以替代父类,而不影响程序的正确性。

3. 依赖倒置原则(Dependency Inversion Principle, DIP)

依赖倒置原则提出,要依赖抽象而不是具体实现。高层模块不应该依赖低层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。

4. 单一职责原则(Single Responsibility Principle, SRP)

单一职责原则要求一个类应该只有一个引起它变化的原因。换句话说,一个类只负责一项职责。这有助于降低类的复杂度,提高其可读性和可维护性。

5. 接口隔离原则(Interface Segregation Principle, ISP)

接口隔离原则要求客户端不应该被迫依赖于它不使用的方法。即接口应当尽量细化,接口中的方法应该尽可能少。这样可以使得接口更灵活,也更容易实现和使用。

6. 最少知识原则(Law of Demeter, LoD)

最少知识原则也叫迪米特法则。它要求一个对象应当对其他对象有尽可能少的了解,只与其直接的朋友通信。这个原则降低了类之间的耦合度,提高了模块的独立性。

7. 合成复用原则(Composite Reuse Principle, CRP)

合成复用原则提出,尽量使用合成/聚合的方式,而不是使用继承来达到代码复用的目的。合成/聚合能使得代码更灵活,降低类与类之间的耦合度。

创建型模式(5种)

1. 简单工厂模式(Simple Factory Pattern)

简单工厂模式是一种创建型设计模式,在一些分类方法中不被认为是一个正式的设计模式,它提供一个创建对象实例的接口,而无需关心其具体实现。通过使用一个工厂类来负责创建对象,客户端代码只需要与工厂类进行交互。

示例代码

public class SimpleFactory {

    public static Product createProduct(String type) {
        if (type.equals("A")) {
            return new ProductA();
        } else if (type.equals("B")) {
            return new ProductB();
        } else {
            throw new IllegalArgumentException("Unknown product type");
        }
    }
}

public interface Product {
    void use();
}

public class ProductA implements Product {
    @Override
    public void use() {
        System.out.println("Using Product A");
    }
}

public class ProductB implements Product {
    @Override
    public void use() {
        System.out.println("Using Product B");
    }
}

public class Client {
    public static void main(String[] args) {
        Product product = SimpleFactory.createProduct("A");
        product.use();
    }
}

2. 工厂方法模式(Factory Method Pattern)

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法使一个类的实例化延迟到其子类。

示例代码

public abstract class Factory {
    public abstract Product createProduct();

    public void doSomething() {
        Product product = createProduct();
        product.use();
    }
}

public class ConcreteFactoryA extends Factory {
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}

public class ConcreteFactoryB extends Factory {
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

public class Client {
    public static void main(String[] args) {
        Factory factory = new ConcreteFactoryA();
        factory.doSomething();
    }
}

3. 抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而无需明确指定具体类。

示例代码

public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB1();
    }
}

public class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB2();
    }
}

public interface ProductA {
    void use();
}

public interface ProductB {
    void eat();
}

public class ProductA1 implements ProductA {
    @Override
    public void use() {
        System.out.println("Using Product A1");
    }
}

public class ProductB1 implements ProductB {
    @Override
    public void eat() {
        System.out.println("Eating Product B1");
    }
}

public class Client {
    private ProductA productA;
    private ProductB productB;

    public Client(AbstractFactory factory) {
        productA = factory.createProductA();
        productB = factory.createProductB();
    }

    public void run() {
        productA.use();
        productB.eat();
    }

    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        Client client1 = new Client(factory1);
        client1.run();

        AbstractFactory factory2 = new ConcreteFactory2();
        Client client2 = new Client(factory2);
        client2.run();
    }
}

4. 单例模式(Singleton Pattern)

单例模式确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。

示例代码

public class Singleton {
    private static Singleton instance;

    private Singleton() {
        // Private constructor to prevent instantiation
    }

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

public class Client {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);  // Output: true
    }
}

5. 建造者模式(Builder Pattern)

建造者模式将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。

示例代码

public class Product {
    private String part1;
    private String part2;

    public void setPart1(String part1) {
        this.part1 = part1;
    }

    public void setPart2(String part2) {
        this.part2 = part2;
    }

    @Override
    public String toString() {
        return "Product [part1=" + part1 + ", part2=" + part2 + "]";
    }
}

public abstract class Builder {
    protected Product product = new Product();

    public abstract void buildPart1();
    public abstract void buildPart2();

    public Product getResult() {
        return product;
    }
}

public class ConcreteBuilder extends Builder {
    @Override
    public void buildPart1() {
        product.setPart1("Part 1");
    }

    @Override
    public void buildPart2() {
        product.setPart2("Part 2");
    }
}

public class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public void construct() {
        builder.buildPart1();
        builder.buildPart2();
    }
}

public class Client {
    public static void main(String[] args) {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        director.construct();
        Product product = builder.getResult();
        System.out.println(product);
    }
}

6. 原型模式(Prototype Pattern)

原型模式是一种创建型设计模式,允许一个对象创建自身的一个拷贝(克隆)。这种模式涉及实现一个原型接口,该接口用于克隆对象。

核心概念

  • 克隆接口(Prototype Interface):定义一个克隆自身的方法。
  • 具体原型(Concrete Prototype):实现克隆接口的具体类。
  • 客户(Client):使用原型实例通过调用克隆方法创建一个新的对象。

适用场景

  • 对象初始化开销大,使用克隆可以提高性能。
  • 系统独立于对象的创建、构成和表示
  • 运行时刻动态决定类实例的创建。

实现

原型模式的实现通常包括以下步骤:

  1. 定义原型接口,包含一个克隆方法。
  2. 实现具体原型类,覆盖克隆方法。
  3. 在客户代码中使用原型实例,通过克隆方法创建新对象。

下面是一个简单的 Java 代码示例:

// Prototype interface
interface Prototype {
    Prototype clone();
}

// Concrete Prototype class
class ConcretePrototype implements Prototype {
    private String field;

    public ConcretePrototype(String field) {
        this.field = field;
    }

    @Override
    public Prototype clone() {
        return new ConcretePrototype(this.field);
    }

    @Override
    public String toString() {
        return "ConcretePrototype [field=" + field + "]";
    }
}

// Client code
public class PrototypePatternDemo {
    public static void main(String[] args) {
        ConcretePrototype prototype = new ConcretePrototype("Initial value");
        ConcretePrototype clone = (ConcretePrototype) prototype.clone();

        System.out.println(prototype);
        System.out.println(clone);
    }
}

在上面的例子中,ConcretePrototype 类实现了 Prototype 接口,并定义了一个 clone 方法,用于创建自身的一个拷贝。客户代码通过调用 clone 方法来创建新的对象。

行为型模式 (Behavioral Patterns)(11种)

1. 模板方法模式(Template Method Pattern)

模板方法模式是一种行为设计模式,它定义了一个算法的框架,并允许子类在不改变算法结构的情况下重新定义该算法的某些步骤。

核心概念

  • 抽象类(Abstract Class):定义模板方法及其步骤。
  • 具体类(Concrete Class):实现模板方法的步骤。

适用场景

  • 多个类具有相似的逻辑,但某些具体步骤有所不同。
  • 代码重复,通过模板方法减少重复代码。

实现

模板方法模式的实现通常包括以下步骤:

  1. 定义抽象类,包含模板方法和抽象步骤。
  2. 实现具体类,覆盖抽象步骤。

下面是一个简单的 Java 代码示例:

// Abstract Class
abstract class AbstractClass {
    // Template Method
    public final void templateMethod() {
        stepOne();
        stepTwo();
        stepThree();
    }

    protected abstract void stepOne();
    protected abstract void stepTwo();
    protected void stepThree() {
        System.out.println("Common Step Three");
    }
}

// Concrete Class
class ConcreteClassA extends AbstractClass {
    @Override
    protected void stepOne() {
        System.out.println("ConcreteClassA Step One");
    }

    @Override
    protected void stepTwo() {
        System.out.println("ConcreteClassA Step Two");
    }
}

// Concrete Class
class ConcreteClassB extends AbstractClass {
    @Override
    protected void stepOne() {
        System.out.println("ConcreteClassB Step One");
    }

    @Override
    protected void stepTwo() {
        System.out.println("ConcreteClassB Step Two");
    }
}

// Client code
public class TemplateMethodPatternDemo {
    public static void main(String[] args) {
        AbstractClass classA = new ConcreteClassA();
        classA.templateMethod();

        AbstractClass classB = new ConcreteClassB();
        classB.templateMethod();
    }
}

在上面的例子中,AbstractClass 定义了一个模板方法 templateMethod,该方法依次调用 stepOnestepTwostepThreeConcreteClassAConcreteClassB 实现了 stepOnestepTwo 方法,而 stepThree 方法在抽象类中提供了默认实现。

2. 迭代器模式(Iterator Pattern)

迭代器模式是一种行为设计模式,它提供了一种方法顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。

核心概念

  • 迭代器接口(Iterator Interface):定义遍历元素的方法。
  • 具体迭代器(Concrete Iterator):实现迭代器接口,负责具体的遍历逻辑。
  • 聚合类(Aggregate Class):定义创建迭代器的方法。
  • 具体聚合类(Concrete Aggregate Class):实现聚合类接口,返回具体迭代器实例。

适用场景

  • 需要访问一个聚合对象的内容,而不需要暴露其内部表示。
  • 需要支持多种遍历方式。
  • 需要为聚合对象提供一个统一的遍历接口。

实现

迭代器模式的实现通常包括以下步骤:

  1. 定义迭代器接口,包含遍历元素的方法。
  2. 实现具体迭代器,负责具体的遍历逻辑。
  3. 定义聚合类,包含创建迭代器的方法。
  4. 实现具体聚合类,返回具体迭代器实例。

下面是一个简单的 Java 代码示例:

import java.util.ArrayList;
import java.util.List;

// Iterator Interface
interface Iterator {
    boolean hasNext();
    Object next();
}

// Concrete Iterator
class ConcreteIterator implements Iterator {
    private List<Object> collection;
    private int position = 0;

    public ConcreteIterator(List<Object> collection) {
        this.collection = collection;
    }

    @Override
    public boolean hasNext() {
        return position < collection.size();
    }

    @Override
    public Object next() {
        return collection.get(position++);
    }
}

// Aggregate Interface
interface Aggregate {
    Iterator createIterator();
}

// Concrete Aggregate
class ConcreteAggregate implements Aggregate {
    private List<Object> collection = new ArrayList<>();

    public void add(Object obj) {
        collection.add(obj);
    }

    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(collection);
    }
}

// Client code
public class IteratorPatternDemo {
    public static void main(String[] args) {
        ConcreteAggregate aggregate = new ConcreteAggregate();
        aggregate.add("Element 1");
        aggregate.add("Element 2");
        aggregate.add("Element 3");

        Iterator iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

3. 观察者模式(Observer Pattern)

观察者模式是一种行为设计模式,定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

核心概念

  • 主题(Subject):维护一组观察者并通知它们状态的改变。
  • 观察者(Observer):定义一个更新接口,用于接收主题的通知。
  • 具体主题(Concrete Subject):实现主题接口,维护具体的观察者集合。
  • 具体观察者(Concrete Observer):实现观察者接口,更新自身状态以响应主题的改变。

适用场景

  • 当一个对象的改变需要同时改变其他对象时,且不知道有多少对象需要改变。
  • 需要对一个对象的状态变化做出响应,而不想与这些对象紧密耦合。

实现

观察者模式的实现通常包括以下步骤:

  1. 定义观察者接口,包含更新方法。
  2. 定义主题接口,包含添加、移除观察者及通知观察者的方法。
  3. 实现具体主题类,维护观察者集合并通知观察者。
  4. 实现具体观察者类,在主题状态改变时更新自身状态。

下面是一个简单的 Java 代码示例:

import java.util.ArrayList;
import java.util.List;

// Observer Interface
interface Observer {
    void update(String state);
}

// Subject Interface
interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

// Concrete Subject
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(state);
        }
    }
}

// Concrete Observer
class ConcreteObserver implements Observer {
    private String name;

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

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

// Client code
public class ObserverPatternDemo {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        Observer observer1 = new ConcreteObserver("Observer 1");
        Observer observer2 = new ConcreteObserver("Observer 2");

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

        subject.setState("State 1");
        subject.setState("State 2");
    }
}

4. 状态模式(State Pattern)

状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为。状态模式通过将每种状态封装到一个独立的类中,使得对象的状态转换成为简单的类间切换。

关键要素

  1. 状态接口(State Interface): 定义所有具体状态类都必须实现的方法。
  2. 具体状态类(Concrete State Classes): 实现状态接口的方法,并封装具体状态的行为。
  3. 上下文类(Context Class): 维护一个当前状态的实例,并在状态变化时进行切换。

实现示例

以电灯开关为例,一个电灯可以有“打开”和“关闭”两种状态。我们通过状态模式来实现它。

状态接口

public interface State {
    void handleRequest();
}

具体状态类

public class OnState implements State {
    @Override
    public void handleRequest() {
        System.out.println("The light is already ON.");
    }
}

public class OffState implements State {
    @Override
    public void handleRequest() {
        System.out.println("The light is now OFF.");
    }
}

上下文类

public class Light {
    private State state;

    public Light() {
        state = new OffState(); // 初始状态为关闭
    }

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

    public void pressButton() {
        state.handleRequest();
        if (state instanceof OffState) {
            setState(new OnState());
        } else {
            setState(new OffState());
        }
    }
}

使用示例

public class StatePatternDemo {
    public static void main(String[] args) {
        Light light = new Light();
        
        light.pressButton(); // 输出:The light is now ON.
        light.pressButton(); // 输出:The light is now OFF.
    }
}

适用场景

  • 对象的行为依赖于其状态,并且必须在运行时根据状态改变其行为。
  • 有大量与对象状态相关的条件语句,状态模式可以通过消除条件语句来提高代码的可维护性和扩展性。

优点

  • 将状态转换逻辑分布到状态类中,简化上下文类的复杂性。
  • 通过增加新的状态类,可以方便地扩展状态,而不需要修改现有代码。

缺点

  • 增加了类的数量,使得代码结构更加复杂。
  • 状态模式可能会导致系统中存在大量的小类,这在某些情况下可能会影响性能。

状态模式通过将不同状态的行为封装到独立的类中,使得对象在不同状态下的行为变化变得更加灵活和易于维护。这种模式非常适合那些状态较多且状态间转换复杂的系统。

5. 策略模式(Strategy Pattern)

策略模式(Strategy Pattern)定义了一系列算法,并将每个算法封装起来,使得它们可以互换。策略模式让算法的变化独立于使用算法的客户。

关键要素

  1. 策略接口(Strategy Interface): 定义算法的通用方法。
  2. 具体策略类(Concrete Strategy Classes): 实现策略接口的具体算法。
  3. 上下文类(Context Class): 维护一个策略对象的引用,用于调用具体策略的方法。

UML 类图

+---------------+        +--------------------+
| Context       |        | Strategy           |
|---------------|        |--------------------|
| - strategy: Strategy |------| + execute()         |
|---------------|        +--------------------+
| + setStrategy()       |            /    |    \
| + executeStrategy()   |           /     |     \
+---------------+       /      +---------------------+  +---------------------+
                        /       | ConcreteStrategyA |  | ConcreteStrategyB |
+---------------------+ +---------------------+  +---------------------+
| + execute()         |  | + execute()         |
+---------------------+  +---------------------+

实现示例

以不同的支付方式为例,我们可以使用策略模式来实现。

策略接口

public interface PaymentStrategy {
    void pay(int amount);
}

具体策略类

public class CreditCardStrategy implements PaymentStrategy {
    private String cardNumber;

    public CreditCardStrategy(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    @Override
    public void pay(int amount) {
        System.out.println("Paid " + amount + " using Credit Card.");
    }
}

public class PayPalStrategy implements PaymentStrategy {
    private String email;

    public PayPalStrategy(String email) {
        this.email = email;
    }

    @Override
    public void pay(int amount) {
        System.out.println("Paid " + amount + " using PayPal.");
    }
}

上下文类

public class ShoppingCart {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void checkout(int amount) {
        paymentStrategy.pay(amount);
    }
}

使用示例

public class StrategyPatternDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        cart.setPaymentStrategy(new CreditCardStrategy("1234-5678-9876-5432"));
        cart.checkout(100); // 输出:Paid 100 using Credit Card.

        cart.setPaymentStrategy(new PayPalStrategy("example@example.com"));
        cart.checkout(200); // 输出:Paid 200 using PayPal.
    }
}

适用场景

  • 需要在运行时选择不同的算法或行为。
  • 有许多相关的类,仅仅在行为上有所不同。
  • 通过不同的算法来完成特定的行为,客户类需要动态地选择不同的算法。

优点

  • 提供了对开闭原则的支持,可以在不修改客户端代码的情况下扩展新的策略。
  • 消除了使用条件语句来选择不同算法的需求,提高代码的可读性和维护性。

缺点

  • 客户必须了解所有策略类的存在,并自行决定使用哪个策略。
  • 增加了系统的复杂性,可能会有大量的策略类。

6. 访问者模式(Visitor Pattern)

访问者模式(Visitor Pattern)是一种行为设计模式,它通过将操作分离到访问者中,允许在不改变元素类的前提下定义作用于这些类的新操作。

关键要素

  1. 访问者接口(Visitor Interface): 定义访问元素的方法。
  2. 具体访问者类(Concrete Visitor Classes): 实现访问者接口,定义具体操作。
  3. 元素接口(Element Interface): 定义接受访问者的方法。
  4. 具体元素类(Concrete Element Classes): 实现元素接口,定义具体元素的行为。

实现示例

以计算购物车中商品的总价和重量为例,我们可以使用访问者模式来实现。

访问者接口

public interface Visitor {
    void visit(Book book);
    void visit(Fruit fruit);
}

具体访问者类

public class PriceVisitor implements Visitor {
    private double totalPrice = 0;

    @Override
    public void visit(Book book) {
        totalPrice += book.getPrice();
    }

    @Override
    public void visit(Fruit fruit) {
        totalPrice += fruit.getPrice() * fruit.getWeight();
    }

    public double getTotalPrice() {
        return totalPrice;
    }
}

public class WeightVisitor implements Visitor {
    private double totalWeight = 0;

    @Override
    public void visit(Book book) {
        // 假设书的重量是固定的
        totalWeight += 1.0;
    }

    @Override
    public void visit(Fruit fruit) {
        totalWeight += fruit.getWeight();
    }

    public double getTotalWeight() {
        return totalWeight;
    }
}

元素接口

public interface Item {
    void accept(Visitor visitor);
}

具体元素类

public class Book implements Item {
    private double price;

    public Book(double price) {
        this.price = price;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

public class Fruit implements Item {
    private double price;
    private double weight;

    public Fruit(double price, double weight) {
        this.price = price;
        this.weight = weight;
    }

    public double getPrice() {
        return price;
    }

    public double getWeight() {
        return weight;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

使用示例

public class VisitorPatternDemo {
    public static void main(String[] args) {
        List<Item> items = new ArrayList<>();
        items.add(new Book(20));
        items.add(new Fruit(10, 2));
        items.add(new Book(15));

        PriceVisitor priceVisitor = new PriceVisitor();
        WeightVisitor weightVisitor = new WeightVisitor();

        for (Item item : items) {
            item.accept(priceVisitor);
            item.accept(weightVisitor);
        }

        System.out.println("Total Price: " + priceVisitor.getTotalPrice()); // 输出:Total Price: 55.0
        System.out.println("Total Weight: " + weightVisitor.getTotalWeight()); // 输出:Total Weight: 4.0
    }
}

适用场景

  • 需要对一个对象结构中的元素进行多种操作,而这些操作需要彼此独立。
  • 需要避免将这些操作逻辑混在元素类中,破坏类的单一职责原则。

优点

  • 增加新的操作变得简单,不需要修改现有元素类。
  • 访问者可以在不修改元素类的前提下,定义新的操作。

缺点

  • 增加新的元素类变得困难,因为所有的访问者都需要修改。
  • 元素类的细节可能对访问者公开,违反了封装原则。

7. 责任链模式 (Chain of Responsibility Pattern)

关键要素

责任链模式是一种行为设计模式,它通过将请求沿着链传递来处理请求,直到有对象处理它为止。每个处理器(处理者)决定是否处理请求以及是否将其传递给链中的下一个处理器。

主要关键要素包括:

  • Handler:定义一个处理请求的接口。
  • ConcreteHandler:具体的处理者类,处理它所负责的请求,可以访问它的后继者。
  • Client:启动链中的请求。

实现示例

// 定义处理请求的接口
abstract class Handler {
    protected Handler successor;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract void handleRequest(int request);
}

// 具体处理者类
class ConcreteHandler1 extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request < 10) {
            System.out.println("ConcreteHandler1 处理请求 " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

class ConcreteHandler2 extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 10 && request < 20) {
            System.out.println("ConcreteHandler2 处理请求 " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

// 客户端代码
public class ChainOfResponsibilityPattern {
    public static void main(String[] args) {
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        handler1.setSuccessor(handler2);

        int[] requests = {1, 5, 12, 18, 24};

        for (int request : requests) {
            handler1.handleRequest(request);
        }
    }
}

适用场景

  • 需要多个对象处理请求时,不希望指定具体的处理者。
  • 处理者链动态组合时。

优点

  • 降低耦合度:请求发送者和接受者解耦。
  • 责任分担:每个处理者只需处理自己能处理的部分。

缺点

  • 性能问题:因为所有请求都必须传递链中的每个处理者。
  • 调试复杂性:因为请求的处理不在一个地方,需要逐步跟踪链。

8. 命令模式 (Command Pattern)

关键要素

命令模式是一种行为设计模式,它将请求封装成对象,从而使您可以使用不同的请求、队列或日志请求来参数化其他对象。命令模式也支持可撤销的操作。

主要关键要素包括:

  • Command:声明执行操作的接口。
  • ConcreteCommand:具体命令,实现Command接口。
  • Invoker:调用者,负责调用命令。
  • Receiver:接收者,执行命令相关的操作。
  • Client:创建具体命令对象并设置其接收者。

实现示例

// 命令接口
interface Command {
    void execute();
}

// 具体命令
class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }
}

// 接收者
class Light {
    public void on() {
        System.out.println("Light is on");
    }

    public void off() {
        System.out.println("Light is off");
    }
}

// 调用者
class RemoteControl {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void pressButton() {
        command.execute();
    }
}

// 客户端代码
public class CommandPattern {
    public static void main(String[] args) {
        Light light = new Light();
        Command lightOn = new LightOnCommand(light);

        RemoteControl remote = new RemoteControl();
        remote.setCommand(lightOn);
        remote.pressButton();
    }
}

适用场景

  • 需要参数化某对象的操作。
  • 需要在不同时间指定、延迟或排队请求
  • 需要支持可撤销的操作

优点

  • 解耦调用者与接收者
  • 扩展性好:新的命令可以很容易地添加。
  • 支持撤销和恢复

缺点

  • 可能导致类数量增多

9. 解释器模式 (Interpreter Pattern)

关键要素

解释器模式是一种行为设计模式,它为某种语言定义其语法表示,并提供一个解释器来处理这种语法。

主要关键要素包括:

  • AbstractExpression:声明一个抽象的解释操作。
  • TerminalExpression:实现与文法中的终结符相关联的解释操作。
  • NonterminalExpression:实现与文法中的非终结符相关联的解释操作。
  • Context:包含解释器之外的一些全局信息。

实现示例

// 表达式接口
interface Expression {
    int interpret(Context context);
}

// 终结符表达式
class Number implements Expression {
    private int number;

    public Number(int number) {
        this.number = number;
    }

    @Override
    public int interpret(Context context) {
        return number;
    }
}

// 非终结符表达式
class Plus implements Expression {
    private Expression leftExpression;
    private Expression rightExpression;

    public Plus(Expression leftExpression, Expression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }

    @Override
    public int interpret(Context context) {
        return leftExpression.interpret(context) + rightExpression.interpret(context);
    }
}

// 环境类
class Context {}

// 客户端代码
public class InterpreterPattern {
    public static void main(String[] args) {
        Expression left = new Number(10);
        Expression right = new Number(20);
        Expression plus = new Plus(left, right);

        Context context = new Context();
        int result = plus.interpret(context);

        System.out.println("Result: " + result); // 输出 30
    }
}

适用场景

  • 当语言的文法较为简单且效率不是关键问题时。
  • 需要解释的语法有较多重复的场景。

优点

  • 易于扩展新的语法
  • 更改和扩展文法较为容易

缺点

  • 复杂文法难以维护
  • 效率较低

10. 备忘录模式 (Memento Pattern)

关键要素

备忘录模式是一种行为设计模式,它在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后可以将对象恢复到之前的状态。

主要关键要素包括:

  • Memento:存储原发器的内部状态。
  • Originator:创建一个备忘录,用以记录当前时刻的内部状态,使用备忘录恢复内部状态。
  • Caretaker:负责保存好备忘录。

实现示例

// 备忘录类
class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

// 发起人类
class Originator {
    private String state;

    public void setState(String state) {
        this.state = state;
        System.out.println("State = " + state);
    }

    public Memento saveStateToMemento() {
        return new Memento(state);
    }

    public void getStateFromMemento(Memento memento) {
        state = memento.getState();
    }
}

// 管理者类
class Caretaker {
    private List<Memento> mementoList = new ArrayList<Memento>();

    public void add(Memento state) {
        mementoList.add(state);
    }

    public Memento get(int index) {
        return mementoList.get(index);
    }
}

// 客户端代码
public class MementoPattern {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.setState("State #1");
        originator.setState("State #2");
        caretaker.add(originator.saveStateToMemento());

        originator.setState("State #3");
        caretaker.add(originator.saveStateToMemento());

        originator.setState("State #4");

        System.out.println("Current State: " + originator.getState());
        originator.getStateFromMemento(caretaker.get(0));
        System.out.println("First saved State: " + originator.getState());
        originator.getStateFromMemento(caretaker.get(1));
        System.out.println("Second saved State: " + originator.getState());
    }
}

适用场景

  • 需要保存和恢复对象的状态时。
  • 需要实现撤销操作时。

优点

  • 封装性好,不会破坏对象的封装性。
  • 简化恢复操作

缺点

  • 消耗资源:保存的状态可能会消耗较多的内存。

11. 中介者模式 (Mediator Pattern)

关键要素

  1. 中介者接口(Mediator Interface):定义与各同事对象(Colleague)的通信接口。
  2. 具体中介者(Concrete Mediator):实现中介者接口,协调各同事对象之间的通信。
  3. 同事类(Colleague Class):持有中介者对象的引用,使用中介者与其他同事类通信。

实现示例

import java.util.ArrayList;
import java.util.List;

// 中介者接口
interface Mediator {
    void notify(Colleague colleague, String message);
}

// 同事类
abstract class Colleague {
    protected Mediator mediator;
    
    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
    
    public abstract void receive(String message);
    public abstract void send(String message);
}

// 具体同事类1
class ConcreteColleague1 extends Colleague {
    public ConcreteColleague1(Mediator mediator) {
        super(mediator);
    }
    
    public void receive(String message) {
        System.out.println("Colleague1 received: " + message);
    }
    
    public void send(String message) {
        System.out.println("Colleague1 sends: " + message);
        mediator.notify(this, message);
    }
}

// 具体同事类2
class ConcreteColleague2 extends Colleague {
    public ConcreteColleague2(Mediator mediator) {
        super(mediator);
    }
    
    public void receive(String message) {
        System.out.println("Colleague2 received: " + message);
    }
    
    public void send(String message) {
        System.out.println("Colleague2 sends: " + message);
        mediator.notify(this, message);
    }
}

// 具体中介者
class ConcreteMediator implements Mediator {
    private List<Colleague> colleagues;
    
    public ConcreteMediator() {
        this.colleagues = new ArrayList<>();
    }
    
    public void addColleague(Colleague colleague) {
        colleagues.add(colleague);
    }
    
    public void notify(Colleague sender, String message) {
        for (Colleague colleague : colleagues) {
            if (colleague != sender) {
                colleague.receive(message);
            }
        }
    }
}

// 测试中介者模式
public class MediatorPatternDemo {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();
        
        Colleague colleague1 = new ConcreteColleague1(mediator);
        Colleague colleague2 = new ConcreteColleague2(mediator);
        
        mediator.addColleague(colleague1);
        mediator.addColleague(colleague2);
        
        colleague1.send("Hello from Colleague1");
        colleague2.send("Hello from Colleague2");
    }
}

适用场景

  • 多个对象之间有复杂的通信关系。
  • 需要通过一个中心点来控制和协调多个对象的交互。

优点

  • 降低对象之间的耦合度。
  • 集中控制交互逻辑,简化对象的通信。

缺点

  • 中介者本身可能变得复杂和难以维护。
  • 增加了系统的开销,因为所有通信都要通过中介者进行。

结构型模式 (Structural Patterns) (7种)

1. 外观模式(Facade Pattern)

外观模式是一种结构型设计模式,它为子系统中的一组接口提供一个统一的接口。外观定义了一个高层接口,使得这一子系统更加容易使用。

核心概念

  • 外观类(Facade Class):提供简化的接口,封装子系统的复杂性。
  • 子系统(Subsystems):复杂的系统或模块。

适用场景

  • 简化复杂系统的使用,提供更高层的接口。
  • 减少客户端与多个子系统间的依赖关系。

实现

外观模式的实现通常包括以下步骤:

  1. 定义外观类,包含简化接口的方法。
  2. 使用外观类,而不是直接与子系统交互。

下面是一个简单的 Java 代码示例:

// Subsystem Class
class SubsystemA {
    public void operationA() {
        System.out.println("SubsystemA operationA");
    }
}

// Subsystem Class
class SubsystemB {
    public void operationB() {
        System.out.println("SubsystemB operationB");
    }
}

// Facade Class
class Facade {
    private SubsystemA subsystemA;
    private SubsystemB subsystemB;

    public Facade() {
        subsystemA = new SubsystemA();
        subsystemB = new SubsystemB();
    }

    public void operation() {
        subsystemA.operationA();
        subsystemB.operationB();
    }
}

// Client code
public class FacadePatternDemo {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.operation();
    }
}

2. 适配器模式 (Adapter Pattern)

关键要素

适配器模式是一种结构型设计模式,它使接口不兼容的对象能够相互合作。通过创建一个适配器类,将一个类的接口转换成客户希望的另一个接口。

主要关键要素包括:

  • Target:定义客户端使用的接口。
  • Adapter:实现Target接口,并包装一个Adaptee对象。
  • Adaptee:定义一个已经存在的接口,客户希望通过适配器使用这个接口。
  • Client:使用Target接口进行调用。

实现示例

// 客户端期望的接口
interface Target {
    void request();
}

// 已经存在的类,具有特殊接口
class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee's specific request.");
    }
}

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

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

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

// 客户端代码
public class AdapterPattern {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.request(); // 输出 Adaptee's specific request.
    }
}

适用场景

  • 希望使用一个已经存在的类,但它的接口不符合你的要求。
  • 创建一个可以复用的类,它可以与不相关或不可见的类协同工作。

优点

  • 解耦目标类和客户端类
  • 提高类的复用性

缺点

  • 增加系统的复杂性
  • 性能可能会受到影响

3. 桥接模式 (Bridge Pattern)

关键要素

桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们都可以独立地变化。通过组合而不是继承来实现功能。

主要关键要素包括:

  • Abstraction:定义抽象类,并包含一个Implementor类型的对象。
  • RefinedAbstraction:扩展Abstraction,具体实现业务方法。
  • Implementor:定义实现类接口。
  • ConcreteImplementor:具体实现Implementor接口。

实现示例

// 实现类接口
interface Implementor {
    void operationImpl();
}

// 具体实现类
class ConcreteImplementorA implements Implementor {
    public void operationImpl() {
        System.out.println("ConcreteImplementorA operation.");
    }
}

class ConcreteImplementorB implements Implementor {
    public void operationImpl() {
        System.out.println("ConcreteImplementorB operation.");
    }
}

// 抽象类
abstract class Abstraction {
    protected Implementor implementor;

    protected Abstraction(Implementor implementor) {
        this.implementor = implementor;
    }

    public abstract void operation();
}

// 扩展抽象类
class RefinedAbstraction extends Abstraction {
    protected RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }

    public void operation() {
        implementor.operationImpl();
    }
}

// 客户端代码
public class BridgePattern {
    public static void main(String[] args) {
        Implementor implementorA = new ConcreteImplementorA();
        Abstraction abstractionA = new RefinedAbstraction(implementorA);
        abstractionA.operation(); // 输出 ConcreteImplementorA operation.

        Implementor implementorB = new ConcreteImplementorB();
        Abstraction abstractionB = new RefinedAbstraction(implementorB);
        abstractionB.operation(); // 输出 ConcreteImplementorB operation.
    }
}

适用场景

  • 需要抽象和实现部分可以独立变化时。
  • 不希望在抽象和实现之间有固定绑定关系时。

优点

  • 分离抽象接口和实现部分
  • 提高系统的扩展性

缺点

  • 增加系统的复杂性

4. 组合模式 (Composite Pattern)

关键要素

组合模式是一种结构型设计模式,它将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。

主要关键要素包括:

  • Component:定义组合对象的接口。
  • Leaf:在组合中表示叶子对象,叶子节点没有子节点。
  • Composite:定义有子部件的那些部件的行为。

实现示例

// 组件接口
interface Component {
    void operation();
}

// 叶子节点
class Leaf implements Component {
    private String name;

    public Leaf(String name) {
        this.name = name;
    }

    @Override
    public void operation() {
        System.out.println("Leaf " + name + " operation.");
    }
}

// 5.组合节点
class Composite implements Component {
    private List<Component> children = new ArrayList<>();

    public void add(Component component) {
        children.add(component);
    }

    public void remove(Component component) {
        children.remove(component);
    }

    public Component getChild(int index) {
        return children.get(index);
    }

    @Override
    public void operation() {
        for (Component child : children) {
            child.operation();
        }
    }
}

// 客户端代码
public class CompositePattern {
    public static void main(String[] args) {
        Composite root = new Composite();
        root.add(new Leaf("Leaf A"));
        root.add(new Leaf("Leaf B"));

        Composite composite = new Composite();
        composite.add(new Leaf("Leaf X"));
        composite.add(new Leaf("Leaf Y"));

        root.add(composite);
        root.operation(); // 输出 Leaf A operation. Leaf B operation. Leaf X operation. Leaf Y operation.
    }
}

适用场景

  • 希望客户端忽略组合对象和单个对象的差异时。
  • 处理树形结构数据时。

优点

  • 定义了包含基本对象和组合对象的类层次结构
  • 简化客户端代码

缺点

  • 可能会导致设计较复杂

5. 装饰器模式 (Decorator Pattern)

关键要素

  1. 组件接口(Component Interface):定义对象的接口,可以被装饰。
  2. 具体组件(Concrete Component):实现组件接口的类。
  3. 装饰器抽象类(Decorator Abstract Class):实现组件接口并持有一个组件对象的引用。
  4. 具体装饰器(Concrete Decorator):扩展装饰器抽象类,增加额外的行为。

实现示例

// 组件接口
interface Component {
    void operation();
}

// 具体组件
class ConcreteComponent implements Component {
    public void operation() {
        System.out.println("ConcreteComponent operation");
    }
}

// 装饰器抽象类
abstract class Decorator implements Component {
    protected Component component;
    
    public Decorator(Component component) {
        this.component = component;
    }
    
    public void operation() {
        component.operation();
    }
}

// 具体装饰器
class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }
    
    public void operation() {
        super.operation();
        addedBehavior();
    }
    
    private void addedBehavior() {
        System.out.println("ConcreteDecoratorA added behavior");
    }
}

// 测试装饰器模式
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        Component decoratedComponent = new ConcreteDecoratorA(component);
        decoratedComponent.operation();
    }
}

适用场景

  • 需要动态地给对象添加功能。
  • 需要通过一种透明的方式来扩展对象的功能。

优点

  • 符合开闭原则,可以动态地扩展对象的功能。
  • 可以通过不同的组合来获得不同行为。

缺点

  • 会产生许多小对象,增加系统复杂性。
  • 装饰器模式比较难以调试。

6. 享元模式 (Flyweight Pattern)

关键要素

  1. 享元接口(Flyweight Interface):定义享元对象的接口。
  2. 具体享元(Concrete Flyweight):实现享元接口并共享内部状态。
  3. 非共享享元(Unshared Flyweight):不被共享的享元对象。
  4. 享元工厂(Flyweight Factory):创建并管理享元对象。

实现示例

import java.util.HashMap;
import java.util.Map;

// 享元接口
interface Flyweight {
    void operation(String extrinsicState);
}

// 具体享元
class ConcreteFlyweight implements Flyweight {
    private String intrinsicState;
    
    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }
    
    public void operation(String extrinsicState) {
        System.out.println("ConcreteFlyweight: intrinsicState = " + intrinsicState + ", extrinsicState = " + extrinsicState);
    }
}

// 非共享享元
class UnsharedConcreteFlyweight implements Flyweight {
    private String allState;
    
    public UnsharedConcreteFlyweight(String allState) {
        this.allState = allState;
    }
    
    public void operation(String extrinsicState) {
        System.out.println("UnsharedConcreteFlyweight: allState = " + allState + ", extrinsicState = " + extrinsicState);
    }
}

// 享元工厂
class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();
    
    public Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteFlyweight(key));
        }
        return flyweights.get(key);
    }
}

// 测试享元模式
public class FlyweightPatternDemo {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        
        Flyweight flyweight1 = factory.getFlyweight("A");
        flyweight1.operation("X");
        
        Flyweight flyweight2 = factory.getFlyweight("B");
        flyweight2.operation("Y");
        
        Flyweight flyweight3 = factory.getFlyweight("A");
        flyweight3.operation("Z");
    }
}

适用场景

  • 一个系统中有大量相似对象,需要避免大量重复的开销。
  • 需要共享对象以节省内存和提高性能。

优点

  • 大幅度减少内存中对象的数量。
  • 提高系统的性能。

缺点

  • 使得系统更加复杂。
  • 需要确保共享对象的内部状态是不变的。

7. 代理模式 (Proxy Pattern)

关键要素

  1. 主题接口(Subject Interface):定义真实对象和代理对象的共同接口。
  2. 真实主题(Real Subject):实现主题接口的真实对象。
  3. 代理(Proxy):持有真实主题的引用,实现主题接口并控制对真实主题的访问。

实现示例

// 主题接口
interface Subject {
    void request();
}

// 真实主题
class RealSubject implements Subject {
    public void request() {
        System.out.println("RealSubject request");
    }
}

// 代理
class Proxy implements Subject {
    private RealSubject realSubject;
    
    public void request() {
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        realSubject.request();
    }
}

// 测试代理模式
public class ProxyPatternDemo {
    public static void main(String[] args) {
        Subject proxy = new Proxy();
        proxy.request();
    }
}

适用场景

  • 需要在访问对象时添加额外的功能,如权限控制、延迟加载和日志记录。
  • 需要控制对真实对象的访问。

优点

  • 控制对真实对象的访问。
  • 可以在代理类中添加额外的功能。

缺点

  • 增加了系统的复杂性。
  • 可能会影响系统的性能。