设计模式通用解释及Java代码用例整理

文章目录

      • 23种设计模式
        • 单例模式(Singleton Pattern)
        • 工厂模式(Factory Pattern)
        • 抽象工厂模式(Abstract Factory Pattern)
        • 建造者模式(Builder Pattern)
        • 原型模式(Prototype Pattern)
        • 适配器模式(Adapter Pattern)
        • 桥接模式(Bridge Pattern)
        • 装饰模式(Decorator Pattern)
        • 代理模式(Proxy Pattern)
        • 外观模式(Facade Pattern)
        • 观察者模式(Observer Pattern)
        • 策略模式(Strategy Pattern)
        • 模板方法模式(Template Method Pattern)
        • 迭代器模式(Iterator Pattern)
        • 组合模式(Composite Pattern)
        • 命令模式(Command Pattern)
        • 备忘录模式(Memento Pattern)
        • 状态模式(State Pattern)
        • 职责链模式(Chain of Responsibility Pattern)
        • 中介者模式(Mediator Pattern)
        • 访问者模式(Visitor Pattern)
        • 解释器模式(Interpreter Pattern)
        • 职责模式(Job Pattern)

设计模式是软件设计中的一些常见模式,它们提供了一种解决特定问题的通用解决方案。这些模式可以帮助开发者更有效地设计和实现软件系统。以下是23种设计模式的通俗解释:

23种设计模式

单例模式(Singleton Pattern)

确保一个类只有一个实例,并提供一个全局访问点。比如,一个系统中只有一个设置或者日志记录的实例。
单例模式在实际应用中非常普遍,例如在数据库连接管理、网络连接管理、缓存管理等场景中。它有助于避免资源的不必要创建,并提供了一个全局访问点来操作该资源。

public class DatabaseConnection {
    private static final DatabaseConnection INSTANCE = new DatabaseConnection();

    private DatabaseConnection() {
        // 初始化数据库连接
        // 这里可以包括连接池的设置等
    }

    public static DatabaseConnection getInstance() {
        return INSTANCE;
    }

    public void executeQuery(String query) {
        // 执行数据库查询
    }
}

// 使用示例
DatabaseConnection connection = DatabaseConnection.getInstance();
connection.executeQuery("select * from users");

// 在这个例子中,DatabaseConnection 类被设计成了单例模式,因此应用程序中所有对数据库的访问都将通过这个唯一的实例来进行,这样可以确保数据库连接的一致性和安全性。
工厂模式(Factory Pattern)

提供一个创建对象的接口,但是由子类决定要实例化的具体类。比如,有一个创建不同类型汽车的工厂,但是用户不需要关心具体实现。
工厂模式就像是有一个专门的工厂,负责生产不同类型的产品。这个工厂有一套标准化的生产流程,但是可以根据客户的需求,生产不同的产品。在软件开发中,这个工厂就是工厂类,它提供了一个接口来创建产品,而具体生产哪种产品则由参数来决定。

例如,有一个汽车工厂,它有一个生产汽车的标准流程。但是,根据客户的需求,这个工厂可以生产不同型号的汽车,比如轿车、SUV或者跑车。客户只需要告诉工厂他们想要哪种汽车,工厂就会生产相应的车型。

// 汽车接口,定义了所有汽车共有的方法
interface Car {
    void start();
    void stop();
}

// 轿车的具体实现
class Sedan implements Car {
    @Override
    public void start() {
        System.out.println("Sedan started.");
    }

    @Override
    public void stop() {
        System.out.println("Sedan stopped.");
    }
}

// SUV的具体实现
class Suv implements Car {
    @Override
    public void start() {
        System.out.println("SUV started.");
    }

    @Override
    public void stop() {
        System.out.println("SUV stopped.");
    }
}

// 工厂类,负责生产不同类型的汽车
class CarFactory {
    public Car createCar(String type) {
        if (type.equals("sedan")) {
            return new Sedan();
        } else if (type.equals("suv")) {
            return new Suv();
        } else {
            throw new IllegalArgumentException("Invalid car type: " + type);
        }
    }
}

// 客户端代码
public class FactoryPatternDemo {
    public static void main(String[] args) {
        CarFactory carFactory = new CarFactory();
        Car sedan = carFactory.createCar("sedan");
        Car suv = carFactory.createCar("suv");

        sedan.start();
        sedan.stop();

        suv.start();
        suv.stop();
    }
}

### 在这个例子中,CarFactory是工厂类,它有一个createCar方法,可以根据客户(FactoryPatternDemo类)的需求创建不同的汽车(SedanSuv)。客户端只需要调用createCar方法并指定想要的汽车类型,就可以获取到相应的汽车对象,而无需关心汽车的具体实现。
抽象工厂模式(Abstract Factory Pattern)

提供一个创建一系列相关对象的接口,而不用指定它们的具体类。比如,游戏中的不同武器和工具的创建。
这个模式的核心思想是,定义一个抽象的工厂接口,该接口提供了创建产品的抽象方法,而具体的产品类则由子工厂类实现。这样,客户端只需要关心如何获取产品,而不需要关心产品的具体实现。

// AbstractFactory: 抽象工厂接口,它定义了创建产品的方法。
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
    // 可以有更多的产品类型
}

// ConcreteFactory1: 具体工厂1,它实现了AbstractFactory接口,并提供了具体的创建产品的方法。
public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        // 创建ProductA的具体实现
        return new ProductAImpl1();
    }

    @Override
    public ProductB createProductB() {
        // 创建ProductB的具体实现
        return new ProductBImpl1();
    }
}

// ConcreteFactory2: 另一个具体工厂2,它也实现了AbstractFactory接口,并提供了不同的产品实现。
public class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        // 创建ProductA的另一个具体实现
        return new ProductAImpl2();
    }

    @Override
    public ProductB createProductB() {
        // 创建ProductB的另一个具体实现
        return new ProductBImpl2();
    }
}

// ProductA和ProductB: 产品接口,它们是抽象工厂生产的不同产品类型。
public interface ProductA {
    // 产品A的相关方法
}

public interface ProductB {
    // 产品B的相关方法
}

// ProductAImpl1和ProductBImpl1: 产品A和产品B的具体实现。
public class ProductAImpl1 implements ProductA {
    // 产品A的实现逻辑
}

public class ProductBImpl1 implements ProductB {
    // 产品B的实现逻辑
}

// ProductAImpl2和ProductBImpl2: 产品A和产品B的另一个具体实现。
public class ProductAImpl2 implements ProductA {
    // 产品A的另一个实现逻辑
}

public class ProductBImpl2 implements ProductB {
    // 产品B的另一个实现逻辑
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        ProductA productA1 = factory1.createProductA();
        ProductB productB1 = factory1.createProductB();

        AbstractFactory factory2 = new ConcreteFactory2();
        ProductA productA2 = factory2.createProductA();
        ProductB productB2 = factory2.createProductB();

        // 客户端代码使用产品,而不关心它们的实现细节
        useProduct(productA1, productB1);
        useProduct(productA2, productB2);
    }

    private static void useProduct(ProductA productA, ProductB productB) {
        // 使用产品A和产品B的方法
    }
}
// 在这个例子中,Client类创建了两个不同工厂的实例,并使用它们来获取产品。Client类不需要关心产品的具体实现,因为所有的创建逻辑都封装在工厂中。这种模式使得在多个产品族之间切换变得很容易,因为只需要更换工厂即可。
建造者模式(Builder Pattern)

将复杂对象的构建与使用分离,使得构建过程可以独立进行。比如,组装一个复杂的机械设备的过程。这种模式的核心思想是“分而治之”,即将复杂对象的创建过程分解为多个简单的步骤,每个步骤都由一个单独的Builder对象负责。

public class CarBuilder {

    private Car car = new Car();

    public CarBuilder setMake(String make) {
        car.setMake(make);
        return this;
    }

    public CarBuilder setModel(String model) {
        car.setModel(model);
        return this;
    }

    public CarBuilder setYear(int year) {
        car.setYear(year);
        return this;
    }

    public CarBuilder setColor(String color) {
        car.setColor(color);
        return this;
    }

    public Car build() {
        return car;
    }
}

public class CarConfiguration {

    @Bean
    public Car getCar() {
        CarBuilder carBuilder = new CarBuilder();
        carBuilder.setMake("Toyota").setModel("Corolla").setYear(2023).setColor("Silver");
        return carBuilder.build();
    }

}
//在这个例子中,CarConfiguration 类使用 @Bean 注解来定义一个 Car 对象,它通过 CarBuilder 来一步步地设置 Car 对象的属性。最终,build() 方法被调用以创建完整的 Car 对象,并将其作为 Bean 注册到 Spring 容器中。通过这种方式,Spring 提供了一种灵活且可扩展的方式来配置和管理对象的创建,这正是建造者模式的核心思想。
原型模式(Prototype Pattern)

通过复制一个对象来创建另一个对象,也就是对象的克隆。比如,在一个游戏里,玩家可以通过复制来创建一个新的角色。

public interface Prototype {
    // 返回此对象的副本
    Prototype clone();
}

// 具体的原型对象实现
public class ConcretePrototype implements Prototype {
    private String name;

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

    @Override
    public Prototype clone() {
        // 使用Java的Cloneable接口来实现深复制或浅复制
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new IllegalStateException("Clone is not supported", e);
        }
    }

    // 其他与名称相关的操作方法
    public String getName() {
        return name;
    }
}

// 客户端代码
public class PrototypeClient {
    public static void main(String[] args) {
        ConcretePrototype prototype = new ConcretePrototype("原始对象");
        ConcretePrototype clone = prototype.clone();
        clone.setName("修改后的对象");

        // 输出结果
        System.out.println("原始对象: " + prototype.getName());
        System.out.println("修改后的对象: " + clone.getName());
    }
}

适配器模式(Adapter Pattern)

将一个类的接口转换为另一个类所需的接口。比如,不同的充电器适配不同类型的手机。

// 老式收音机,只能播放AM信号
class OldRadio {
    public void playAM(String amStation) {
        // 播放AM信号
    }
}

// 新式收音机,能够播放FM信号
class NewRadio {
    public void playFM(String fmStation) {
        // 播放FM信号
    }
}

// FM适配器,适配老式收音机,使得其能够播放FM信号
class FmAdapter extends OldRadio {
    private NewRadio newRadio;

    public FmAdapter() {
        this.newRadio = new NewRadio();
    }

    @Override
    public void playAM(String amStation) {
        // 老式收音机播放AM信号
    }

    public void playFM(String fmStation) {
        // 使用新式收音机播放FM信号
        this.newRadio.playFM(fmStation);
    }
}

// 使用适配器
public class Main {
    public static void main(String[] args) {
        OldRadio oldRadio = new FmAdapter();
        oldRadio.playFM("FM101.7"); // 通过适配器调用新式收音机的播放方法
    }
}
//在这个例子中,FmAdapter类继承了OldRadio类,并提供了playFM方法。在playFM方法内部,它调用NewRadio类的playFM方法来播放FM信号。这样,通过FmAdapter,OldRadio就能够播放FM信号了。
桥接模式(Bridge Pattern)

将抽象与实现分离,使它们可以独立变化。比如,一个音乐播放器,音乐格式和播放器界面可以独立变化。

//有一个系统,需要处理不同类型的文件(例如PDF、Word文档等),每种类型的文件都需要进行不同的操作(例如打开、关闭、打印等)。我们可以使用桥接模式来设计这个系统。

// 抽象化层
interface FileHandler {
    void openFile();
    void closeFile();
    void printFile();
}

// 实现化层
class PdfFileHandler implements FileHandler {
    @Override
    public void openFile() {
        // 打开PDF文件的逻辑
    }

    @Override
    public void closeFile() {
        // 关闭PDF文件的逻辑
    }

    @Override
    public void printFile() {
        // 打印PDF文件的逻辑
    }
}

class WordFileHandler implements FileHandler {
    @Override
    public void openFile() {
        // 打开Word文档的逻辑
    }

    @Override
    public void closeFile() {
        // 关闭Word文档的逻辑
    }

    @Override
    public void printFile() {
        // 打印Word文档的逻辑
    }
}

// 桥接层
class FileManager {
    private FileHandler fileHandler;

    public void setFileHandler(FileHandler fileHandler) {
        this.fileHandler = fileHandler;
    }

    public void handleFile() {
        fileHandler.openFile();
        // 其他文件处理逻辑
        fileHandler.closeFile();
    }
}

// 使用桥接模式
FileManager fileManager = new FileManager();
fileManager.setFileHandler(new PdfFileHandler());
fileManager.handleFile(); // 处理PDF文件

fileManager.setFileHandler(new WordFileHandler());
fileManager.handleFile(); // 处理Word文档

//在这个例子中,FileManager 类使用了桥接模式,它依赖于 FileHandler 接口,但并不关心具体实现。你可以随时更换 FileHandler 的实现,而不会影响 FileManager 的代码。桥接模式使得系统更加灵活,易于扩展。
装饰模式(Decorator Pattern)

在不改变原有对象的基础上,通过增加额外的功能来扩展对象。比如,在咖啡中加入不同的调料,如糖和奶油。

// 抽象组件(被装饰的对象)
interface Beverage {
    double cost();
    String getDescription();
}

// 具体组件(被装饰的具体对象)
class Coffee extends Beverage {
    @Override
    public double cost() {
        return 1.5;
    }

    @Override
    public String getDescription() {
        return "Coffee";
    }
}

// 抽象装饰类
interface Decorator extends Beverage {
    // 提供添加装饰的方法
    Beverage decorate(Beverage beverage);
}

// 具体装饰类1(增加杯盖)
class CoffeeWithToppings extends Decorator {
    private Beverage beverage;

    public CoffeeWithToppings(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.5; // 假设杯盖增加的成本
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " with toppings";
    }

    @Override
    public Beverage decorate(Beverage beverage) {
        return new CoffeeWithToppings(beverage);
    }
}

// 客户端代码
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Beverage coffee = new Coffee();
        Beverage coffeeWithToppings = new CoffeeWithToppings(coffee);
        System.out.println("Cost of " + coffeeWithToppings.getDescription() + " is " + coffeeWithToppings.cost());
    }
}

//在这个例子中,Beverage 是抽象组件,Coffee 是具体组件。Decorator 是抽象装饰类,CoffeeWithToppings 是具体装饰类,它继承了 Decorator 并实现了装饰方法 decorate(Beverage beverage)。客户端代码可以动态地创建带有不同装饰的饮料对象。
代理模式(Proxy Pattern)

为另一个对象提供一个替身或代表,以便控制对这个对象的访问。比如,在网络游戏中,玩家可以使用一个代理来控制角色。

// 抽象主题(Subject)接口
public interface Subject {
    void doSomething();
}

// 真实主题(RealSubject)类
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject: Doing something real.");
    }
}

// 代理主题(ProxySubject)类
public class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject() {
        // 懒加载,仅在需要时创建真实对象
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
    }

    @Override
    public void doSomething() {
        // 可以在这里添加额外的逻辑,比如记录日志或性能监控
        System.out.println("ProxySubject: Pre-processing...");
        realSubject.doSomething();
        System.out.println("ProxySubject: Post-processing...");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Subject subject = new ProxySubject();
        subject.doSomething(); // 通过代理对象调用真实对象的方法
    }
}

外观模式(Facade Pattern)

为子系统中的一组接口提供一个一致的界面。外观模式就像是汽车的方向盘。当你开车时,你不需要关心汽车引擎、变速器、离合器等内部部件是如何工作的。你只需要通过方向盘来控制汽车,如加速、减速、转向等。方向盘简化了你对汽车的操控,它隐藏了复杂的机械和电子系统,为你提供了一个简单的接口。

// 汽车类(复杂的子系统)
class Car {
    public void startEngine() {
        System.out.println("启动引擎");
    }

    public void accelerate() {
        System.out.println("加速");
    }

    public void brake() {
        System.out.println("刹车");
    }

    public void turnLeft() {
        System.out.println("向左转");
    }

    public void turnRight() {
        System.out.println("向右转");
    }
}

// 外观类(提供简单的接口)
class CarFacade {
    private Car car;

    public CarFacade() {
        this.car = new Car();
    }

    // 简化的方法,背后调用Car类的方法
    public void drive() {
        car.startEngine();
        car.accelerate();
        car.turnLeft();
        car.turnRight();
        car.brake();
    }
}

// 使用外观类
public class Main {
    public static void main(String[] args) {
        CarFacade carFacade = new CarFacade();
        carFacade.drive();
    }
}
//在这个例子中,CarFacade类是外观类,它隐藏了Car类的复杂性。当你调用CarFacade的drive()方法时,它会在幕后调用Car类中的各个方法来模拟一个驾驶过程。这样,你就不需要直接操作Car类的复杂方法,而是通过CarFacade来完成一系列的操作。在实际应用中,外观模式非常适合那些想要隐藏其内部复杂性并提供一个简单接口的系统。它可以帮助你简化客户端与子系统的交互,使得系统更易于使用和维护。
观察者模式(Observer Pattern)

当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。比如,在用户注册时发送邮件和短信通知。
Java 中观察者模式的实现通常涉及两个核心接口:Observable(被观察者)和 Observer(观察者)。

//创建一个被观察者类(Observable)
import java.util.List;
import java.util.Observable;
import java.util.Observer;

public class Subject extends Observable {
    private String data;

    public void setData(String data) {
        this.data = data;
        setChanged(); // 标记状态已更改
        notifyObservers(data); // 通知所有观察者
    }
}

//创建一个观察者类(Observer)
import java.util.Observable;
import java.util.Observer;

public class Observer implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        // 当被观察者状态变化时,观察者会收到通知
        System.out.println("收到通知:" + arg);
    }
}

//订阅和通知:观察者可以订阅被观察者,并在被观察者状态变化时收到通知
import java.util.List;
import java.util.Observable;
import java.util.Observer;

public class Main {
    public static void main(String[] args) {
        Subject subject = new Subject();
        Observer observer = new Observer();
        subject.addObserver(observer);

        subject.setData("这是最新的数据"); // 设置数据并通知观察者
    }
}

//在上面的例子中,Subject 类是一个被观察者,它维护了一个 Observable 对象,并重写了 setData 方法来设置数据并通知观察者。Observer 类是一个观察者,它实现了 Observer 接口,并在 update 方法中处理被观察者发送的通知。Main 类演示了如何创建一个被观察者和观察者,并让它们相互订阅和通知。
策略模式(Strategy Pattern)

定义一系列算法,并在运行时选择使用哪一个算法。比如,不同的信用卡支付方式。

// 行为接口
interface Strategy {
    void algorithm();
}

// 行为1:快速算法
class FastAlgorithm implements Strategy {
    @Override
    public void algorithm() {
        System.out.println("执行快速算法");
    }
}

// 行为2:慢速算法
class SlowAlgorithm implements Strategy {
    @Override
    public void algorithm() {
        System.out.println("执行慢速算法");
    }
}

// 上下文类,它持有一个Strategy对象
class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void execute() {
        strategy.algorithm();
    }
}

// 使用策略模式
public class StrategyPatternDemo {
    public static void main(String[] args) {
        Strategy slowAlgorithm = new SlowAlgorithm();
        Strategy fastAlgorithm = new FastAlgorithm();

        Context context = new Context(slowAlgorithm);
        context.execute(); // 执行慢速算法

        context.setStrategy(fastAlgorithm);
        context.execute(); // 切换到快速算法
    }
}
//在这个例子中,Strategy 接口定义了一个算法,FastAlgorithm 和 SlowAlgorithm 类实现了不同的算法。Context 类包含一个 Strategy 对象,并通过 setStrategy 方法来切换不同的策略。StrategyPatternDemo 类展示了如何使用策略模式来切换算法。
模板方法模式(Template Method Pattern)

定义一个操作的骨架,将一些步骤延迟到子类中。比如,一个烹饪菜谱,步骤是固定的,但具体的配料和做法可以变化。

public abstract class AbstractTemplate {
    public final void templateMethod() {
        step1();
        step2();
        step3();
    }

    protected abstract void step1();

    protected abstract void step2();

    protected void step3() {
        // 这里的步骤3是固定的,不需要子类实现
        System.out.println("Step 3 performed.");
    }
}

public class ConcreteTemplate extends AbstractTemplate {
    @Override
    protected void step1() {
        System.out.println("ConcreteTemplate: Step 1 performed.");
    }

    @Override
    protected void step2() {
        System.out.println("ConcreteTemplate: Step 2 performed.");
    }
}

public class TemplateMethodTest {
    public static void main(String[] args) {
        AbstractTemplate abstractTemplate = new ConcreteTemplate();
        abstractTemplate.templateMethod();
    }
}

//在这个例子中,AbstractTemplate 类定义了操作的模板 templateMethod(),并提供了 step3() 的具体实现。ConcreteTemplate 类继承自 AbstractTemplate,并重写了 step1() 和 step2() 方法,提供了具体的操作。TemplateMethodTest 类用于测试模板方法模式。当 TemplateMethodTest 类调用 abstractTemplate.templateMethod() 时,AbstractTemplate 类的 templateMethod() 方法会被执行,它首先调用 step1(),然后是 step2(),最后是 step3()。因为 step3() 已经在 AbstractTemplate 类中实现,所以它不会被 ConcreteTemplate 类重写。
迭代器模式(Iterator Pattern)

提供一种方法来顺序访问一个聚合对象中的各个元素。比如,一个用于遍历列表或数组的迭代器。

MyList<Integer> list = new MyList<>(new Integer[] {1, 2, 3, 4, 5});
Iterator<Integer> iterator = list.iterator();

while (iterator.hasNext()) {
    Integer element = iterator.next();
    System.out.println(element);
}

组合模式(Composite Pattern)

将对象组合成树形结构,以表示“部分-整体”的层次结构。比如,一个公司的组织结构。

// 抽象组件(Component)
interface Component {
    void add(Component child);
    void remove(Component child);
    void print(); // 打印方法,用于演示
}

// 叶节点(Leaf)
class Leaf implements Component {
    @Override
    public void add(Component child) {
        // 叶节点没有子节点,所以这个方法不做任何事情
    }

    @Override
    public void remove(Component child) {
        // 叶节点没有子节点,所以这个方法不做任何事情
    }

    @Override
    public void print() {
        System.out.println("Leaf node"); // 叶节点的打印逻辑
    }
}

// 组合对象(Composite)
class Composite implements Component {
    private List<Component> children = new ArrayList<>();

    @Override
    public void add(Component child) {
        children.add(child);
    }

    @Override
    public void remove(Component child) {
        children.remove(child);
    }

    @Override
    public void print() {
        System.out.println("Composite node"); // 组合对象的打印逻辑
        for (Component child : children) {
            child.print();
        }
    }
}

// 客户端代码
public class CompositePattern {
    public static void main(String[] args) {
        Component root = new Composite();
        root.add(new Leaf()); // 添加叶节点
        root.add(new Leaf()); // 添加另一个叶节点
        root.add(new Composite()); // 添加一个组合对象
        root.print(); // 打印整个组合
    }
}
//在这个例子中,Component是抽象组件,Leaf是叶节点,Composite是组合对象。Composite对象可以包含其他Component对象,而Leaf对象则没有子节点。print方法在组合模式中非常重要,它允许我们以一致的方式遍历整个组合并打印每个组件。在实际应用中,组合模式常用于GUI开发、文件系统和XML解析器等场景。
命令模式(Command Pattern)

将一个请求封装成一个对象,从而允许使用不同的请求、队列或日志来参数化其他对象。比如,一个远程控制的命令列表。

// 定义命令的接口
interface Command {
    void execute();
    void undo();
}

// 具体命令的实现类
class ConcreteCommand implements Command {
    private Receiver receiver;

    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.doSomething(); // 调用接收者的操作
    }

    @Override
    public void undo() {
        receiver.undoSomething(); // 调用接收者的撤销操作
    }
}

// 接收者接口,定义了具体操作
interface Receiver {
    void doSomething();
    void undoSomething();
}

// 具体接收者的实现类
class ConcreteReceiver implements Receiver {
    @Override
    public void doSomething() {
        System.out.println("Doing something...");
    }

    @Override
    public void undoSomething() {
        System.out.println("Undoing something...");
    }
}

// 客户端类,创建命令并执行
class Client {
    public static void main(String[] args) {
        Receiver receiver = new ConcreteReceiver();
        Command command = new ConcreteCommand(receiver);

        command.execute(); // 执行命令
        command.undo(); // 撤销命令
    }
}

//在这个例子中,Command 接口定义了 execute() 和 undo() 方法,表示执行命令和撤销命令。ConcreteCommand 类实现了 Command 接口,并持有 Receiver 对象,这样它就可以调用 Receiver 的操作。ConcreteReceiver 类实现了 Receiver 接口,定义了实际的执行和撤销操作。Client 类创建了一个 Command 对象并调用其 execute() 和 undo() 方法。
备忘录模式(Memento Pattern)

在不泄露内部状态的情况下,捕获一个对象的内部状态,并在之后恢复到该状态。比如,游戏中的存档和读档功能。

public class GameState {
    private int score;
    private int level;

    // 创建备忘录
    public Memento createMemento() {
        return new Memento(this.score, this.level);
    }

    // 恢复备忘录
    public void restoreMemento(Memento memento) {
        this.score = memento.getScore();
        this.level = memento.getLevel();
    }
}

public class Memento {
    private int score;
    private int level;

    public Memento(int score, int level) {
        this.score = score;
        this.level = level;
    }

    public int getScore() {
        return score;
    }

    public int getLevel() {
        return level;
    }
}

public class GamePlayer {
    private GameState gameState;

    // 保存游戏状态
    public void saveGameState() {
        Memento memento = gameState.createMemento();
        // 这里可以将备忘录存储在文件、数据库或其他持久化介质中
    }

    // 恢复游戏状态
    public void restoreGameState() {
        Memento memento = // 从文件、数据库等加载备忘录
        gameState.restoreMemento(memento);
    }
}

状态模式(State Pattern)

允许对象在内部状态改变时改变它的行为。比如,一个自动售货机根据投入的硬币数量和选择的商品来改变状态。

// 状态接口
interface State {
    void insertCoin();
    void selectItem();
    void dispenseItem();
    void refundCoin();
}

// 状态类(具体状态1:有足够的硬币)
class State1 implements State {
    @Override
    public void insertCoin() {
        // 如果有足够的硬币,增加硬币数量
        System.out.println("状态1: 插入硬币,硬币数量增加");
    }

    @Override
    public void selectItem() {
        // 如果有足够的硬币,允许选择商品
        System.out.println("状态1: 选择商品");
    }

    @Override
    public void dispenseItem() {
        // 如果有足够的硬币,发放商品
        System.out.println("状态1: 发放商品");
    }

    @Override
    public void refundCoin() {
        // 如果有足够的硬币,退回硬币
        System.out.println("状态1: 退回硬币");
    }
}

// 状态类(具体状态2:硬币不足)
class State2 implements State {
    @Override
    public void insertCoin() {
        // 硬币不足,提示投入更多的硬币
        System.out.println("状态2: 硬币不足,请投入更多硬币");
    }

    @Override
    public void selectItem() {
        // 硬币不足,不允许选择商品
        System.out.println("状态2: 硬币不足,不允许选择商品");
    }

    @Override
    public void dispenseItem() {
        // 硬币不足,不允许发放商品
        System.out.println("状态2: 硬币不足,不允许发放商品");
    }

    @Override
    public void refundCoin() {
        // 硬币不足,不允许退回硬币
        System.out.println("状态2: 硬币不足,不允许退回硬币");
    }
}

// 上下文类
class Context {
    private State state;

    public Context(State state) {
        this.state = state;
    }

    public void insertCoin() {
        state.insertCoin();
    }

    public void selectItem() {
        state.selectItem();
    }

    public void dispenseItem() {
        state.dispenseItem();
    }

    public void refundCoin() {
        state.refundCoin();
    }

    // 可以根据需要添加改变状态的方法
    public void changeState(State newState) {
        state = newState;
    }
}

public class StatePatternDemo {
    public static void main(String[] args) {
        Context context = new Context(new State1());
        context.insertCoin(); // 插入硬币,状态1
        context.selectItem(); // 选择商品,状态1
        context.dispenseItem(); // 发放商品,状态1
        context.refundCoin(); // 退回硬币,状态1

        // 假设硬币不足,改变状态
        context.changeState(new State2());

        context.insertCoin(); // 硬币不足,状态2
        context.selectItem(); // 硬币不足,状态2
        context.dispenseItem(); // 硬币不足,状态2
        context.refundCoin(); // 硬币不足,状态2
    }
}
//在这个例子中,State 接口定义了售货机可能执行的操作。State1 和 State2 是两个具体状态类,它们分别表示售货机有足够的硬币和硬币不足时的行为。Context 类负责维护当前状态,并提供操作方法。在 main 方法中,我们创建了一个 Context 对象,并设置了初始状态。然后,我们通过调用 insertCoin, selectItem, dispenseItem 和 refundCoin 方法来改变售货机的状态并观察其行为。最后,我们模拟硬币不足的情况,通过 changeState 方法改变状态,并观察新的行为。
职责链模式(Chain of Responsibility Pattern)

将请求的发送者和接收者解耦,使得可以在链中传递请求,直到有一个对象处理它。比如,在一个公司中,问题的上报和解决流程。

import java.util.LinkedList;
import java.util.List;

// 抽象Handler类
abstract class Handler {
    Handler successor; // 指向下一个Handler

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

    public abstract void handleRequest();
}

// 具体Handler子类1: Level1Handler
class Level1Handler extends Handler {
    public void handleRequest() {
        // 如果Level1Handler可以处理请求,处理它
        if (canHandleRequest()) {
            System.out.println("Level1Handler handling request...");
        } else {
            // 如果不能处理,传递给下一个Handler
            if (successor != null) {
                successor.handleRequest();
            } else {
                System.out.println("No more handlers, request ignored.");
            }
        }
    }

    // 假设这个方法用于检查是否可以处理请求
    private boolean canHandleRequest() {
        // 这里可以添加具体的条件判断
        return true; // 或者根据需要返回其他结果
    }
}

// 具体Handler子类2: Level2Handler
class Level2Handler extends Handler {
    public void handleRequest() {
        // 同上
        if (canHandleRequest()) {
            System.out.println("Level2Handler handling request...");
        } else {
            if (successor != null) {
                successor.handleRequest();
            } else {
                System.out.println("No more handlers, request ignored.");
            }
        }
    }

    private boolean canHandleRequest() {
        // 这里可以添加具体的条件判断
        return true; // 或者根据需要返回其他结果
    }
}

// 创建一个Handler链
public class ChainExample {
    public static void main(String[] args) {
        Handler level1 = new Level1Handler();
        Handler level2 = new Level2Handler();

        // 将level1设置为level2的successor
        level1.setSuccessor(level2);

        // 开始处理请求
        level1.handleRequest();
    }
}
//在这个例子中,Level1Handler 和 Level2Handler 是具体的Handler子类,它们各自负责特定的请求处理。在main方法中,我们创建了两个Handler对象,并将第一个Handler(Level1Handler)设置为第二个Handler(Level2Handler)的successor。然后,我们调用Level1Handler的handleRequest方法来开始处理请求。如果Level1Handler可以处理请求,它就会处理;如果不能,它会传递给Level2Handler。如果Level2Handler也不能处理,那么请求将会被忽略,因为successor为null,表明这是Handler链的末端。在实际应用中,职责链模式可以用于日志记录、异常处理、事件分发器和访问控制等领域。
中介者模式(Mediator Pattern)

减少对象之间的直接通信。中介者对象封装了一系列对象交互,使得对象不需要彼此直接引用。比如,在团队合作中,使用项目管理工具来协调不同成员的工作。

//抽象中介者接口,它定义了各个参与者之间可以进行的操作
public interface Mediator {
    void register(Colleague colleague);
    void sendMessage(Colleague sender, Colleague receiver, String message);
}

//中介者类,它维护一个参与者(同事)列表,并负责转发消息
public class ConcreteMediator implements Mediator {
    private List<Colleague> colleagues = new ArrayList<>();

    @Override
    public void register(Colleague colleague) {
        colleagues.add(colleague);
    }

    @Override
    public void sendMessage(Colleague sender, Colleague receiver, String message) {
        // 转发消息给接收者
        receiver.receiveMessage(sender, message);
    }
}

//参与者的抽象类,它定义了接受消息的方法
public abstract class Colleague {
    private Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }

    public void sendMessage(Colleague receiver, String message) {
        mediator.sendMessage(this, receiver, message);
    }

    public abstract void receiveMessage(Colleague sender, String message);
}

//实现具体的参与者类,它们通过中介者进行通信
public class ConcreteColleagueA extends Colleague {
    public ConcreteColleagueA(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void receiveMessage(Colleague sender, String message) {
        // 处理收到的消息
        System.out.println("ColleagueA received message: " + message + " from " + sender.getClass().getSimpleName());
    }
}

public class ConcreteColleagueB extends Colleague {
    public ConcreteColleagueB(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void receiveMessage(Colleague sender, String message) {
        // 处理收到的消息
        System.out.println("ColleagueB received message: " + message + " from " + sender.getClass().getSimpleName());
    }
}

//使用中介者模式
public class Main {
    public static void main(String[] args) {
        Mediator mediator = new ConcreteMediator();
        Colleague colleagueA = new ConcreteColleagueA(mediator);
        Colleague colleagueB = new ConcreteColleagueB(mediator);

        // 注册参与者
        mediator.register(colleagueA);
        mediator.register(colleagueB);

        // 发送消息
        colleagueA.sendMessage(colleagueB, "Hello from ColleagueA");
        colleagueB.sendMessage(colleagueA, "Hello from ColleagueB");
    }
}

//在这个例子中,ConcreteMediator 类是中介者,它管理着 ConcreteColleagueA 和 ConcreteColleagueB 的通信。每个参与者只需要通过中介者发送消息,而不需要知道其他参与者的具体细节。这种设计使得系统的结构更加清晰,且更容易维护和扩展。
访问者模式(Visitor Pattern)

表示一个作用于某对象结构中的各个元素的操作。比如,对不同类型的文件进行统计和分析。

// 抽象元素
abstract class Element {
    public abstract void accept(Visitor visitor);
}

// 具体元素1
class ConcreteElement1 extends Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 具体元素2
class ConcreteElement2 extends Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 访问者
interface Visitor {
    void visit(Element element);
}

// 具体访问者
class ConcreteVisitor implements Visitor {
    @Override
    public void visit(Element element) {
        if (element instanceof ConcreteElement1) {
            ((ConcreteElement1) element).operate1();
        } else if (element instanceof ConcreteElement2) {
            ((ConcreteElement2) element).operate2();
        } else {
            throw new IllegalArgumentException("Unknown element type: " + element.getClass().getName());
        }
    }
}

// 使用访问者
Element element1 = new ConcreteElement1();
Element element2 = new ConcreteElement2();

Visitor visitor = new ConcreteVisitor();
element1.accept(visitor);
element2.accept(visitor);

//在这个例子中,Element 是抽象元素,ConcreteElement1 和 ConcreteElement2 是具体元素,Visitor 是访问者接口,ConcreteVisitor 是具体访问者。accept 方法和 visit 方法是访问者模式的核心,它们允许访问者对元素执行特定的操作。
解释器模式(Interpreter Pattern)

提供解释一种语言的语法表示的机制。比如,一个简单的计算器,可以解释和执行简单的数学表达式。这种模式通常用于构建简单的语言解析器,例如配置文件解析、简单的脚本语言解释器或者命令行工具等。

// 操作接口
interface IOperation {
    int interpret(int a, int b);
}

// 操作类(+, -, *, /)
class PlusOperation implements IOperation {
    @Override
    public int interpret(int a, int b) {
        return a + b;
    }
}

class MinusOperation implements IOperation {
    @Override
    public int interpret(int a, int b) {
        return a - b;
    }
}

// 解释器类
class ArithmeticExpressionInterpreter {
    private IOperation operation;

    public ArithmeticExpressionInterpreter(IOperation operation) {
        this.operation = operation;
    }

    public int interpret(String expression) {
        // 解析表达式并执行
        String[] parts = expression.split(" ");
        int a = Integer.parseInt(parts[0]);
        int b = Integer.parseInt(parts[1]);
        return operation.interpret(a, b);
    }
}

public class Main {
    public static void main(String[] args) {
        IOperation plusOperation = new PlusOperation();
        IOperation minusOperation = new MinusOperation();

        ArithmeticExpressionInterpreter interpreter = new ArithmeticExpressionInterpreter(plusOperation);
        int result = interpreter.interpret("10 20"); // 输出: 30
        System.out.println(result);

        interpreter = new ArithmeticExpressionInterpreter(minusOperation);
        result = interpreter.interpret("10 20"); // 输出: -10
        System.out.println(result);
    }
}

//在这个例子中,IOperation 接口定义了操作的协议,而 PlusOperation 和 MinusOperation 类实现了这些操作。ArithmeticExpressionInterpreter 类则负责解释表达式并执行相应的操作。Main 类展示了如何创建解释器并使用它来解释简单的算术表达式。
职责模式(Job Pattern)

将一个大任务分解成小任务,每个小任务都可以独立执行。比如,项目管理中的任务分解。
这些模式并不是孤立使用的,它们可以结合在一起解决更复杂的设计问题。了解这些模式可以帮助开发者更好地理解软件设计中的问题和解决方案。

public abstract class RequestHandler {
    public abstract void handleRequest(Request request);
}

public class ConcreteRequestHandler1 extends RequestHandler {
    @Override
    public void handleRequest(Request request) {
        // 检查请求是否属于自己的职责
        if (request.getType() == RequestType.TYPE1) {
            // 处理请求
            handleType1Request(request);
        } else {
            // 转发请求给其他处理器
            ConcreteRequestHandler2 otherHandler = new ConcreteRequestHandler2();
            otherHandler.handleRequest(request);
        }
    }

    private void handleType1Request(Request request) {
        // 处理类型1的请求
    }
}

public class ConcreteRequestHandler2 extends RequestHandler {
    @Override
    public void handleRequest(Request request) {
        // 检查请求是否属于自己的职责
        if (request.getType() == RequestType.TYPE2) {
            // 处理请求
            handleType2Request(request);
        } else {
            // 转发请求给其他处理器
            ConcreteRequestHandler1 otherHandler = new ConcreteRequestHandler1();
            otherHandler.handleRequest(request);
        }
    }

    private void handleType2Request(Request request) {
        // 处理类型2的请求
    }
}

public class Client {
    public static void main(String[] args) {
        RequestHandler handler1 = new ConcreteRequestHandler1();
        RequestHandler handler2 = new ConcreteRequestHandler2();

        // 发送请求给处理程序,处理程序会根据请求类型进行相应处理
        handler1.handleRequest(new Request(RequestType.TYPE1));
        handler2.handleRequest(new Request(RequestType.TYPE2));
    }
}

//在这个例子中,RequestHandler 是抽象类,定义了处理请求的抽象方法。ConcreteRequestHandler1 和 ConcreteRequestHandler2 是具体处理类,它们分别负责处理不同类型的请求。当 Client 发送请求时,RequestHandler 会根据请求的类型选择相应的处理类来处理请求。如果请求不属于自己的职责,就会转发给其他处理类。这种方式可以确保每个请求都有对应的处理程序,同时处理程序之间是松耦合的,便于维护和扩展。

你可能感兴趣的:(设计模式,java,好理解)