23种常用设计模式介绍

发布于:2025-07-26 ⋅ 阅读:(16) ⋅ 点赞:(0)

设计模式(Design Pattern)是指在软件开发过程中,针对反复出现的问题所总结归纳出的通用解决方案。这些方案由四位作者(Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides)在1994年合著的《设计模式-可复用的面向对象软件元素》一书中首次提出,因此也被称为"四人帮(Gang of Four,GoF)"设计模式。

设计模式主要分为三大类:创建型模式、结构型模式和行为型模式。本文将对这23种常用设计模式进行简要介绍,并提供Java代码示例。

设计模式
创建型模式
结构型模式
行为型模式
单例模式
工厂模式
抽象工厂模式
建造者模式
原型模式
适配器模式
桥接模式
组合模式
装饰器模式
外观模式
享元模式
代理模式
责任链模式
命令模式
解释器模式
迭代器模式
中介者模式
备忘录模式
观察者模式
状态模式
策略模式
模板方法模式
访问者模式

一、创建型模式(Creational Patterns)

创建型模式主要用于对象的创建过程,关注如何灵活、高效地创建对象。它主要解决对象的创建问题,封装复杂的创建过程,解耦对象的创建代码和使用代码。

1. 单例模式(Singleton Pattern)

单例模式用来创建全局唯一的对象。确保一个类只有一个实例,并提供一个全局访问点。单例有几种经典的实现方式,它们分别是:饿汉式、懒汉式、双重检测、静态内部类、枚举。

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

2. 工厂模式(Factory Pattern)

通过工厂模式定义一个创建对象的接口,让子类决定实例化哪个类。

工厂模式用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。实际上,如果创建对象的逻辑并不复杂,那我们直接通过new来创建对象就可以了,不需要使用工厂模式。当创建逻辑比较复杂,是一个“大工程”的时候,我们就考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离。

当每个对象的创建逻辑都比较简单的时候,我推荐使用简单工厂模式,将多个对象的创建逻辑放到一个工厂类中。当每个对象的创建逻辑都比较复杂的时候,为了避免设计一个过于庞大的工厂类,我们推荐使用工厂方法模式,将创建逻辑拆分得更细,每个对象的创建逻辑独立到各自的工厂类中。

// 产品接口
interface Shape {
    void draw();
}

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

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing Rectangle");
    }
}

// 工厂类
class ShapeFactory {
    public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
            return new Rectangle();
        }
        return null;
    }
}

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

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式的应用场景比较特殊,在实际开发过程中较少用到。

// 抽象工厂接口
interface AbstractFactory {
    Shape getShape(String shapeType);
    Color getColor(String colorType);
}

// 具体工厂
class ShapeFactory implements AbstractFactory {
    @Override
    public Shape getShape(String shapeType) {
        // 实现略,同工厂模式示例
        return null;
    }
    
    @Override
    public Color getColor(String colorType) {
        return null;
    }
}

class ColorFactory implements AbstractFactory {
    @Override
    public Shape getShape(String shapeType) {
        return null;
    }
    
    @Override
    public Color getColor(String colorType) {
        // 实现略
        return null;
    }
}

4. 建造者模式(Builder Pattern)

建造者模式用来创建复杂对象,可以通过设置不同的可选参数,“定制化”地创建不同的对象。它将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。

class Computer {
	// CPU
    private String cpu;
    // 内存
    private String ram;
    // 硬盘存储
    private String storage;
    
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
        this.storage = builder.storage;
    }
    
    // Getters
    
    static class Builder {
        private String cpu;
        private String ram;
        private String storage;
        
        public Builder setCpu(String cpu) {
            this.cpu = cpu;
            return this;
        }
        
        public Builder setRam(String ram) {
            this.ram = ram;
            return this;
        }
        
        public Builder setStorage(String storage) {
            this.storage = storage;
            return this;
        }
        
        public Computer build() {
            return new Computer(this);
        }
    }
}

5. 原型模式(Prototype Pattern)

如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(拷贝)的方式,来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型模式。

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

import java.util.Hashtable;

// 原型类
abstract class Shape implements Cloneable {
    private String id;
    protected String type;
    
    abstract void draw();
    
    public String getType() {
        return type;
    }
    
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

// 具体原型类
class Circle extends Shape {
    public Circle() {
        type = "Circle";
    }
    
    @Override
    public void draw() {
        System.out.println("Drawing Circle");
    }
}

// 原型管理器
class ShapeCache {
    private static Hashtable<String, Shape> shapeMap = new Hashtable<>();
    
    public static Shape getShape(String shapeId) {
        Shape cachedShape = shapeMap.get(shapeId);
        return (Shape) cachedShape.clone();
    }
    
    // 加载缓存
    public static void loadCache() {
        Circle circle = new Circle();
        circle.setId("1");
        shapeMap.put(circle.getId(), circle);
        
        // 其他形状的缓存加载...
    }
}

二、结构型模式(Structural Patterns)

结构型模式主要用于处理类或对象的组合,关注如何将类或对象结合在一起形成更大的结构。

6. 适配器模式(Adapter Pattern)

适配器模式是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。

// 目标接口
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 被适配的类
class AdvancedMediaPlayer {
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }
    
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: " + fileName);
    }
}

// 适配器
class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedMediaPlayer;
    
    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMediaPlayer = new AdvancedMediaPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMediaPlayer = new AdvancedMediaPlayer();
        }
    }
    
    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMediaPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMediaPlayer.playMp4(fileName);
        }
    }
}

// 具体实现类
class AudioPlayer implements MediaPlayer {
    private MediaAdapter mediaAdapter;
    
    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing mp3 file. Name: " + fileName);
        } else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Invalid media. " + audioType + " format not supported");
        }
    }
}

7. 桥接模式(Bridge Pattern)

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

// 实现接口
interface Color {
    void applyColor();
}

// 具体实现
class RedColor implements Color {
    @Override
    public void applyColor() {
        System.out.println("Applying red color");
    }
}

class GreenColor implements Color {
    @Override
    public void applyColor() {
        System.out.println("Applying green color");
    }
}

// 抽象类
abstract class Shape {
    protected Color color;
    
    public Shape(Color color) {
        this.color = color;
    }
    
    abstract void draw();
}

// 具体抽象类
class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }
    
    @Override
    void draw() {
        System.out.println("Drawing Circle");
        color.applyColor();
    }
}

class Rectangle extends Shape {
    public Rectangle(Color color) {
        super(color);
    }
    
    @Override
    void draw() {
        System.out.println("Drawing Rectangle");
        color.applyColor();
    }
}

8. 组合模式(Composite Pattern)

组合模式主要是用来处理树形结构数据,它将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。正因为其应用场景的特殊性,数据必须能表示成树形结构,这也导致了这种模式在实际的项目开发中并不那么常用。

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

// 组件接口
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");
    }
}

// 组合节点
class Composite implements Component {
    private List<Component> children = new ArrayList<>();
    private String name;
    
    public Composite(String name) {
        this.name = name;
    }
    
    public void add(Component component) {
        children.add(component);
    }
    
    public void remove(Component component) {
        children.remove(component);
    }
    
    @Override
    public void operation() {
        System.out.println("Composite " + name + " operation");
        for (Component child : children) {
            child.operation();
        }
    }
}

9. 装饰器模式(Decorator Pattern)

装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承,给原始类添加增强功能。它动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活。

装饰器模式还有一个特点,那就是可以对原始类嵌套使用多个装饰器。为了满足这样的需求,在设计的时候,装饰器类需要跟原始类继承相同的抽象类或者接口。

// 接口
interface Shape {
    void draw();
}

// 具体组件
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Shape: Rectangle");
    }
}

// 装饰器抽象类
abstract class ShapeDecorator implements Shape {
    protected Shape decoratedShape;
    
    public ShapeDecorator(Shape decoratedShape) {
        this.decoratedShape = decoratedShape;
    }
    
    @Override
    public void draw() {
        decoratedShape.draw();
    }
}

// 具体装饰器
class RedShapeDecorator extends ShapeDecorator {
    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }
    
    @Override
    public void draw() {
        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }
    
    private void setRedBorder(Shape decoratedShape) {
        System.out.println("Border Color: Red");
    }
}

10. 门面(外观)模式(Facade Pattern)

为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用,或者解决性能、分布式事务等问题。。

// 子系统类
class CPU {
    public void start() {
        System.out.println("CPU started");
    }
    
    public void shutdown() {
        System.out.println("CPU shutdown");
    }
}

class Memory {
    public void load() {
        System.out.println("Memory loaded");
    }
    
    public void unload() {
        System.out.println("Memory unloaded");
    }
}

class HardDrive {
    public void read() {
        System.out.println("HardDrive read");
    }
    
    public void write() {
        System.out.println("HardDrive write");
    }
}

// 外观类
class ComputerFacade {
    private CPU cpu;
    private Memory memory;
    private HardDrive hardDrive;
    
    public ComputerFacade() {
        this.cpu = new CPU();
        this.memory = new Memory();
        this.hardDrive = new HardDrive();
    }
    
    public void startComputer() {
        cpu.start();
        memory.load();
        hardDrive.read();
        System.out.println("Computer started successfully");
    }
    
    public void shutdownComputer() {
        cpu.shutdown();
        memory.unload();
        hardDrive.write();
        System.out.println("Computer shutdown successfully");
    }
}

11. 享元模式(Flyweight Pattern)

享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。它运用共享技术有效地支持大量细粒度的对象。该模式在项目开发中较少使用。

具体来讲,当一个系统中存在大量重复对象的时候,我们就可以利用享元模式,将对象设计成享元,在内存中只保留一份实例,供多处代码引用,这样可以减少内存中对象的数量,以起到节省内存的目的。实际上,不仅仅相同对象可以设计成享元,对于相似对象,我们也可以将这些对象中相同的部分(字段),提取出来设计成享元,让这些大量相似对象引用这些享元。

import java.util.HashMap;

// 享元接口
interface Shape {
    void draw();
}

// 具体享元类
class Circle implements Shape {
    private String color;
    private int x;
    private int y;
    private int radius;
    
    public Circle(String color) {
        this.color = color;
    }
    
    public void setX(int x) {
        this.x = x;
    }
    
    public void setY(int y) {
        this.y = y;
    }
    
    public void setRadius(int radius) {
        this.radius = radius;
    }
    
    @Override
    public void draw() {
        System.out.println("Circle: Draw() [Color : " + color + ", x : " + x + ", y : " + y + ", radius : " + radius);
    }
}

// 享元工厂
class ShapeFactory {
    private static final HashMap<String, Shape> circleMap = new HashMap<>();
    
    public static Shape getCircle(String color) {
        Circle circle = (Circle) circleMap.get(color);
        
        if (circle == null) {
            circle = new Circle(color);
            circleMap.put(color, circle);
            System.out.println("Creating circle of color : " + color);
        }
        return circle;
    }
}

12. 代理模式(Proxy Pattern)

代理模式为其他对象提供一种代理以控制对这个对象的访问。代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。一般情况下,我们让代理类和原始类实现同样的接口。但是,如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。在这种情况下,我们可以通过让代理类继承原始类的方法来实现代理模式。

代理模式常用在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。我们将这些附加功能与业务功能解耦,放到代理类统一处理,让开发人员只需要关注业务方面的开发。除此之外,代理模式还可以用在RPC、缓存等应用场景中。

// 接口
interface Image {
    void display();
}

// 真实主题
class RealImage implements Image {
    private String fileName;
    
    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk(fileName);
    }
    
    @Override
    public void display() {
        System.out.println("Displaying " + fileName);
    }
    
    private void loadFromDisk(String fileName) {
        System.out.println("Loading " + 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();
    }
}

三、行为型模式(Behavioral Patterns)

行为型模式主要用于处理类或对象之间的交互问题,关注对象之间的通信和职责分配。行为型模式比较多,有11种,它们分别是:观察者模式、模板方法模式、策略模式、责任链模式、迭代器模式、状态模式、访问者模式、备忘录模式、命令模式、解释器模式、中介者模式。

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

在责任链模式中,多个处理器依次处理同一个请求。一个请求先经过A处理器处理,然后再把请求传递给B处理器,B处理器处理完后再传递给C处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作责任链模式。

责任链使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

责任链模式常用在框架开发中,用来实现过滤器、拦截器功能,让框架的使用者在不需要修改框架源码的情况下,添加新的过滤、拦截功能。

// 抽象处理者
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 >= 0 && request < 10) {
            System.out.println("ConcreteHandler1 handled request " + 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 handled request " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

class ConcreteHandler3 extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 20 && request < 30) {
            System.out.println("ConcreteHandler3 handled request " + request);
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

14. 命令模式(Command Pattern)

命令模式将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。命令模式在日常开发中应用场景较少。

命令模式的主要作用和应用场景,是用来控制命令的执行,比如,异步、延迟、排队执行命令、撤销重做命令、存储命令、给命令记录日志等,这才是命令模式能发挥独一无二作用的地方。

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

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

// 具体命令
class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.turnOn();
    }
}

class LightOffCommand implements Command {
    private Light light;
    
    public LightOffCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.turnOff();
    }
}

// 调用者
class RemoteControl {
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
    }
}

15. 解释器模式(Interpreter Pattern)

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

它的代码实现的核心思想,就是将语法解析的工作拆分到各个小类中,以此来避免大而全的解析类。一般的做法是,将语法规则拆分一些小的独立的单元,然后对每个单元进行解析,最终合并为对整个语法规则的解析。

// 表达式接口
interface Expression {
    boolean interpret(String context);
}

// 终结符表达式
class TerminalExpression implements Expression {
    private String data;
    
    public TerminalExpression(String data) {
        this.data = data;
    }
    
    @Override
    public boolean interpret(String context) {
        return context.contains(data);
    }
}

// 非终结符表达式
class OrExpression implements Expression {
    private Expression expr1;
    private Expression expr2;
    
    public OrExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }
    
    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) || expr2.interpret(context);
    }
}

class AndExpression implements Expression {
    private Expression expr1;
    private Expression expr2;
    
    public AndExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }
    
    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) && expr2.interpret(context);
    }
}

16. 迭代器模式(Iterator Pattern)

迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。迭代器模式也叫游标模式,它用来遍历集合对象。这里说的“集合对象”,我们也可以叫“容器”“聚合对象”,实际上就是包含一组对象的对象,比如,数组、链表、树、图、跳表。迭代器模式主要作用是解耦容器代码和遍历代码。大部分编程语言都提供了现成的迭代器可以使用,我们不需要从零开始开发。

遍历集合一般有三种方式:for循环、foreach循环、迭代器遍历。后两种本质上属于一种,都可以看作迭代器遍历。相对于for循环遍历,利用迭代器来遍历有3个优势:

  • 迭代器模式封装集合内部的复杂数据结构,开发人员不需要了解如何遍历,直接使用容器提供的迭代器即可;
  • 迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一;
  • 迭代器模式让添加新的遍历算法更加容易,更符合开闭原则。除此之外,因为迭代器都实现自相同的接口,在开发中,基于接口而非实现编程,替换迭代器也变得更加容易。
// 迭代器接口
interface Iterator {
    boolean hasNext();
    Object next();
}

// 聚合接口
interface Container {
    Iterator getIterator();
}

// 具体聚合
class NameRepository implements Container {
    public String[] names = {"Robert", "John", "Julie", "Lora"};
    
    @Override
    public Iterator getIterator() {
        return new NameIterator();
    }
    
    private class NameIterator implements Iterator {
        int index;
        
        @Override
        public boolean hasNext() {
            return index < names.length;
        }
        
        @Override
        public Object next() {
            if (this.hasNext()) {
                return names[index++];
            }
            return null;
        }
    }
}

17. 中介者模式(Mediator Pattern)

用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

观察者模式和中介模式都是为了实现参与者之间的解耦,简化交互关系。两者的不同在于应用场景上。

  • 在观察者模式的应用场景中,参与者之间的交互比较有条理,一般都是单向的,一个参与者只有一个身份,要么是观察者,要么是被观察者。
  • 而在中介模式的应用场景中,参与者之间的交互关系错综复杂,既可以是消息的发送者、也可以同时是消息的接收者。
// 中介者接口
interface ChatMediator {
    void sendMessage(String msg, User user);
    void addUser(User user);
}

// 具体中介者
class ChatMediatorImpl implements ChatMediator {
    private List<User> users;
    
    public ChatMediatorImpl() {
        this.users = new ArrayList<>();
    }
    
    @Override
    public void sendMessage(String msg, User user) {
        for (User u : this.users) {
            if (u != user) {
                u.receive(msg);
            }
        }
    }
    
    @Override
    public void addUser(User user) {
        this.users.add(user);
    }
}

// 同事类
abstract class User {
    protected ChatMediator mediator;
    protected String name;
    
    public User(ChatMediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
    }
    
    public abstract void send(String msg);
    public abstract void receive(String msg);
}

// 具体同事类
class UserImpl extends User {
    public UserImpl(ChatMediator mediator, String name) {
        super(mediator, name);
    }
    
    @Override
    public void send(String msg) {
        System.out.println(this.name + ": Sending Message = " + msg);
        mediator.sendMessage(msg, this);
    }
    
    @Override
    public void receive(String msg) {
        System.out.println(this.name + ": Received Message: " + msg);
    }
}

18. 备忘录模式(Memento Pattern)

备忘录模式也叫快照模式,就是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。

这个模式的定义表达了两部分内容:一部分是,存储副本以便后期恢复;另一部分是,要在不违背封装原则的前提下,进行对象的备份和恢复。

// 备忘录类
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;
    }
    
    public String getState() {
        return state;
    }
    
    public Memento saveStateToMemento() {
        return new Memento(state);
    }
    
    public void getStateFromMemento(Memento memento) {
        state = memento.getState();
    }
}

// 管理者类
class CareTaker {
    private List<Memento> mementoList = new ArrayList<>();
    
    public void add(Memento state) {
        mementoList.add(state);
    }
    
    public Memento get(int index) {
        return mementoList.get(index);
    }
}

19. 观察者模式(Observer Pattern)

观察者模式将观察者和被观察者代码解耦。观察者模式的应用场景非常广泛,小到代码层面的解耦,大到架构层面的系统解耦,再或者一些产品的设计思路,都有这种模式的影子,比如,邮件订阅、RSS Feeds,本质上都是观察者模式。

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

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

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

// 具体主题
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;
    
    public int getState() {
        return state;
    }
    
    public void setState(int state) {
        this.state = state;
        notifyObservers();
    }
    
    @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();
        }
    }
}

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

// 具体观察者
class ConcreteObserver implements Observer {
    private ConcreteSubject subject;
    private int observerState;
    
    public ConcreteObserver(ConcreteSubject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }
    
    @Override
    public void update() {
        observerState = subject.getState();
        System.out.println("Observer state updated to: " + observerState);
    }
}

20. 状态模式(State Pattern)

状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

状态模式一般用来实现状态机,而状态机常用在游戏、工作流引擎等系统开发中。状态机又叫有限状态机,它由3个部分组成:状态、事件、动作。其中,事件也称为转移条件。事件触发状态的转移及动作的执行。不过,动作不是必须的,也可能只转移状态,不执行任何动作。

// 状态接口
interface State {
    void doAction(Context context);
}

// 具体状态
class StartState implements State {
    @Override
    public void doAction(Context context) {
        System.out.println("Player is in start state");
        context.setState(this);
    }
    
    @Override
    public String toString() {
        return "Start State";
    }
}

class StopState implements State {
    @Override
    public void doAction(Context context) {
        System.out.println("Player is in stop state");
        context.setState(this);
    }
    
    @Override
    public String toString() {
        return "Stop State";
    }
}

// 上下文
class Context {
    private State state;
    
    public Context() {
        state = null;
    }
    
    public void setState(State state) {
        this.state = state;
    }
    
    public State getState() {
        return state;
    }
}

21. 策略模式(Strategy Pattern)

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

策略模式用来解耦策略的定义、创建、使用。实际上,一个完整的策略模式就是由这三个部分组成的。策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。策略的创建由工厂类来完成,封装策略创建的细节。策略模式包含一组策略可选,客户端代码选择使用哪个策略,有两种确定方法:编译时静态确定和运行时动态确定。其中,“运行时动态确定”才是策略模式最典型的应用场景。

// 策略接口
interface Strategy {
    int doOperation(int num1, int num2);
}

// 具体策略
class OperationAdd implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }
}

class OperationSubtract implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 - num2;
    }
}

class OperationMultiply implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 * num2;
    }
}

// 上下文
class Context {
    private Strategy strategy;
    
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public int executeStrategy(int num1, int num2) {
        return strategy.doOperation(num1, num2);
    }
}

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

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

模板方法模式有两大作用:复用和扩展。其中复用指的是,所有的子类可以复用父类中提供的模板方法的代码。扩展指的是,框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架源码的情况下,基于扩展点定制化框架的功能。

// 抽象类
abstract class Game {
    abstract void initialize();
    abstract void startPlay();
    abstract void endPlay();
    
    // 模板方法
    public final void play() {
        // 初始化游戏
        initialize();
        
        // 开始游戏
        startPlay();
        
        // 结束游戏
        endPlay();
    }
}

// 具体类
class Cricket extends Game {
    @Override
    void initialize() {
        System.out.println("Cricket Game Initialized! Start playing.");
    }
    
    @Override
    void startPlay() {
        System.out.println("Cricket Game Started. Enjoy the game!");
    }
    
    @Override
    void endPlay() {
        System.out.println("Cricket Game Finished!");
    }
}

class Football extends Game {
    @Override
    void initialize() {
        System.out.println("Football Game Initialized! Start playing.");
    }
    
    @Override
    void startPlay() {
        System.out.println("Football Game Started. Enjoy the game!");
    }
    
    @Override
    void endPlay() {
        System.out.println("Football Game Finished!");
    }
}

23. 访问者模式(Visitor Pattern)

访问者模式表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

访问者模式允许一个或者多个操作应用到一组对象上,设计意图是解耦操作和对象本身,保持类职责单一、满足开闭原则以及应对代码的复杂性。

// 元素接口
interface ComputerPart {
    void accept(ComputerPartVisitor computerPartVisitor);
}

// 具体元素
class Keyboard implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

class Monitor implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

class Mouse implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        computerPartVisitor.visit(this);
    }
}

class Computer implements ComputerPart {
    private ComputerPart[] parts;
    
    public Computer() {
        parts = new ComputerPart[]{new Mouse(), new Keyboard(), new Monitor()};
    }
    
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
        for (ComputerPart part : parts) {
            part.accept(computerPartVisitor);
        }
        computerPartVisitor.visit(this);
    }
}

// 访问者接口
interface ComputerPartVisitor {
    void visit(Computer computer);
    void visit(Mouse mouse);
    void visit(Keyboard keyboard);
    void visit(Monitor monitor);
}

// 具体访问者
class ComputerPartDisplayVisitor implements ComputerPartVisitor {
    @Override
    public void visit(Computer computer) {
        System.out.println("Displaying Computer.");
    }
    
    @Override
    public void visit(Mouse mouse) {
        System.out.println("Displaying Mouse.");
    }
    
    @Override
    public void visit(Keyboard keyboard) {
        System.out.println("Displaying Keyboard.");
    }
    
    @Override
    public void visit(Monitor monitor) {
        System.out.println("Displaying Monitor.");
    }
}

总结

设计模式是软件开发中宝贵的经验总结,它们提供了通用的解决方案来解决常见的设计问题。掌握这23种设计模式可以帮助开发人员更好地组织代码,提高代码的可维护性、可扩展性和可复用性。在实际项目开发中,我们需要根据具体需求合理选择和应用设计模式,避免过度设计。


网站公告

今日签到

点亮在社区的每一天
去签到