3628 字
18 分钟
设计模式笔记(行为型模式)
2025-10-25
无标签

设计模式#

行为型模式#

重点关注对象之间是如何通信的

模板方法模式#

定义了一个算法架构,允许子类为一个或者多个步骤实现

模板方法在子类不改变算法结构的情况下,重新定义算法某些步骤

实现算法的不变部分,并将可变的空间留给子类完成

子类中公共的行为抽出出来并封装到一个公共的父类中,避免代码重复

设计抽象类,其中约定一个流程,流程控制交由flag函数进行控制,实现的子类可以重写这个函数进行对于父类流程改变

public abstract class AClass {
    public final void makeClass() {
        makePPT();
        makeVideo();
        if(flag()) {
            makeJava();
            doJava();
        }
    }
    public final void makePPT() {
        System.out.println("制作PPT");
    }
    public final void makeVideo() {
        System.out.println("制作Video");
    }
    public final void makeJava() {
        System.out.println("编写JAVA");
    }
    protected boolean flag() {
        return false;
    }
    public abstract void doJava();
}

实现类,重写flag方法

public class JavaClass extends AClass{
    private boolean flag;

    public JavaClass(boolean flag) {
        this.flag = flag;
    }

    @Override
    protected boolean flag() {
        return flag;
    }

    @Override
    public void doJava() {
        System.out.println("设计模式代码");
    }
}

实际调用传入true,那么在制作课程的时候执行java相关的业务

public class Main {
    public static void main(String[] args) {
        AClass javaClass = new JavaClass(true);
        javaClass.makeClass();
    }
}

这样我们实现子类的时候可以自定义父类模板流程,进行灵活增加删除一些流程

迭代器模式#

提供方法,顺序访问集合中的各个元素,而不暴露对象的内部表示

为遍历不同的集合结构提供了统一的接口,分离了集合对象的遍历行为

迭代器接口,使用泛型作为拓展

public interface Iterator<T> {
    boolean hasNext();
    T next();
}

书籍迭代器实现

public class BookIterator implements Iterator<Book>{
    private Book[] books;
    private int index = 0;
    public BookIterator(Book[] books) {
        this.books = books;
    }

    @Override
    public boolean hasNext() {
        return index < books.length && books[index] != null;
    }

    @Override
    public Book next() {
        return books[index++];
    }
}

通过创建和传入books数组,即可通过迭代器获取各个元素

public interface Library {
    Iterator<Book> createIterator();
}
public class BookLibrary implements Library {
    private Book[] books;
    public BookLibrary(Book[] books) {
        this.books = books;
    }

    @Override
    public Iterator<Book> createIterator() {
        return new BookIterator(books);
    }
}
public class Main {
    public static void main(String[] args) {
        Book[] books = {new Book(), new Book(), new Book()};
        Library library = new BookLibrary(books);
        Iterator<Book> iterator = library.createIterator();
        while (iterator.hasNext()) {
            Book book = iterator.next();
            System.out.println(book);
        }
    }
}

策略模式#

定义了算法,分别封装起来,他们之间可以相互替换,让算法的变化不会影响到使用算法的用户

如果有大量的if-else可以通过策略模式进行替换

提报算法的保密性

现有一个算法的接口,传入两个参数

public interface Strategy {
    int operator(int n1, int n2);
}

加法实现

public class Add implements Strategy {
    @Override
    public int operator(int n1, int n2) {
        return n1 + n2;
    }
}

减法实现

public class Sub implements Strategy {
    @Override
    public int operator(int n1, int n2) {
        return n1 - n2;
    }
}

策略类,其中有算法的接口对象

public class Operation {
    private Strategy strategy;

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

    public int execute(int n1, int n2) {
        return strategy.operator(n1, n2);
    }
}

使用的时候传入对应算法实现即可

public class Main {
    public static void main(String[] args) {
        Operation operation = new Operation(new Add());
        System.out.println(operation.execute(1, 2));
    }
}

解释器模式#

通过给定的语言,定义它的语法和行为,并定义解释器,用这个解释器来解释语言中的句子

为解释一种语言,而为语言创建的解释器

某个类型的语言触发频次够高,比如处理日志和不同日志格式

解释器接口

public interface Expression {
    boolean interpret(String context);
}

解释器实现,传入带解释的数据,实现中实现解释逻辑

public class TerminalExpression implements Expression{
    private String data;
    public TerminalExpression(String data) {
        this.data = data;
    }
    @Override
    public boolean interpret(String context) {
        return context.contains(data);
    }
}
public class Main {
    public static void main(String[] args) {
        Expression expression = new TerminalExpression("hello");
        System.out.println(expression.interpret("hello world"));
    }
}

观察者模式#

当存在一对多关系的时候,可以使用观察者模式

比如,当一个对象被修改的时候,则会自动通知依赖他的对象

让对多个观察者对象同时监听某一个主题对象,当主题对象发生改变的时候,它所有依赖者(观察者)都会收到通知并更新

主题类

设计一个主题类,其中包含了观察者对象列表,观察对象state,以及绑定方法(将观察者添加到观察者列表中)

在state的set方法上设立通知的方法,当set观察对象被修改的时候,发出通知,去依次执行观察者中的方法

public class Subject {
    private List<Observer> observerList = new ArrayList<>();
    private int state;
    public void bind(Observer observer) {
        observerList.add(observer);
    }

    public int getState() {
        return state;
    }

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

    public void notifyObservers() {
        for (Observer observer : observerList) {
            observer.update();
        }
    }
}

观察者抽象类

由对应的抽象方法供通知方法调用,交由子类实现

public abstract class Observer {
    protected Subject subject;
    public abstract void update();
}

观察者实现

在构造方法中传入主题对象,由主题对象进行对于观察者的绑定,实现主题通知观察者的方法

public class HexObserver extends Observer {
    public HexObserver(Subject subject) {
        this.subject = subject;
        this.subject.bind(this);
    }

    @Override
    public void update() {
        System.out.println("转换为16进制:" + Integer.toHexString(subject.getState()));
    }
}

调用:创建主题对象,创建观察者并绑定到主题上,当主题监听字段发送改变的时候触发通知调用观察者更新方法

public class Main {
    public static void main(String[] args) {
        Subject subject = new Subject();
        new HexObserver(subject);
        System.out.println("状态值为:15");
        subject.setState(15);
    }
}

备忘录模式#

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态

现在有一个文本编辑器,可以编辑并提供撤销功能

// 1. Memento(存储编辑器状态)
public class TextMemento {
    private final String content;  // 状态保存的内容

    public TextMemento(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }
}
// 2. Originator(需要保存状态的类)
public class TextEditor {
    private String content;

    public void write(String text) {
        this.content = text;
    }

    public String getContent() {
        return content;
    }

    // 创建备忘录(保存当前状态)
    public TextMemento save() {
        return new TextMemento(this.content);
    }

    // 恢复状态
    public void restore(TextMemento memento) {
        this.content = memento.getContent();
    }
}
// 3. Caretaker(管理备忘录)
public class HistoryManager {
    private Stack<TextMemento> history = new Stack<>();

    public void save(TextMemento memento) {
        history.push(memento);
    }

    public TextMemento undo() {
        if (!history.isEmpty()) {
            return history.pop();  // 返回上一个状态
        }
        return null;
    }
}

客户端调用

public class Client {
    public static void main(String[] args) {
        // 初始化
        TextEditor editor = new TextEditor();
        HistoryManager history = new HistoryManager();

        // 编辑并保存
        editor.write("Hello");  // 第一次编辑
        history.save(editor.save());  // 保存状态1

        editor.write("Hello World");  // 第二次编辑
        history.save(editor.save());  // 保存状态2

        editor.write("Hello Java");   // 第三次编辑
        System.out.println("Current Content: " + editor.getContent());  // "Hello Java"

        // 撤销一次(回到 "Hello World")
        editor.restore(history.undo());
        System.out.println("After Undo: " + editor.getContent());  // "Hello World"

        // 再撤销一次(回到 "Hello")
        editor.restore(history.undo());
        System.out.println("After 2nd Undo: " + editor.getContent());  // "Hello"
    }
}

命令模式#

将一个请求封装为一个对象,从而可以用不同的请求对于客户进行参数化,解决了应用程序中对象的职责以及它们之间的通信方式

在软件系统中,行为请求者和行为实现者通常是一种紧耦合的关系,但在某些场合,比如需要对行为进行记录,撤销或者重做,事务等处理的时候,这种无法抵御变化的紧耦合的设计就不太合适

请求调用者和行为实现者需要解耦,使得调用者和行为实现者不直接交互

由一个类型的股票,可以买入卖出

public class Stock {
    private String name;
    private int count = 10;
    public void buy() {
        System.out.println("购买:" + name +  "股票-" + count);
    }
    public void sell() {
        System.out.println("卖出:" + name +  "股票-" + count);
    }
}

现在有命令接口

public interface Order {
    void execute();
}

实现命令

public class BuyStock implements Order {
    private Stock stock;

    public BuyStock(Stock stock) {
        this.stock = stock;
    }

    @Override
    public void execute() {
        stock.buy();
    }
}
public class SellStock implements Order{
    private Stock stock;

    public SellStock(Stock stock) {
        this.stock = stock;
    }

    @Override
    public void execute() {
        stock.sell();
    }
}

中间的代理者,可以向其中传入命令,暴露方法统一执行

public class Broker {
    List<Order> orders = new ArrayList<Order>();
    public void takeOrder(Order order) {
        orders.add(order);
    }
    public void placeOrder() {
        for (Order order : orders) {
            order.execute();
        }
        orders.clear();
    }
}
public class Main {
    public static void main(String[] args) {
        Stock stock = new Stock();
        Broker broker = new Broker();
        broker.takeOrder(new BuyStock(stock));
        broker.takeOrder(new SellStock(stock));
        broker.placeOrder();
    }
}

中介者模式#

用于降低多个对象之间通信的复杂性,提供一个中介类,通常处理不同类之间的通信,并支持松耦合,使代码易于维护

中介者类

public class Role {
    public static void work(User user, String message) {
        System.out.println("Role work");
        System.out.println("User: " + user.getName());
        System.out.println("Message: " + message);
    }
}

在User中调用中介者的方法

public class User {
    private String name;

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

    public String getName() {
        return name;
    }
    public void sendMessage(String message) {
        Role.work(this, message);
    }
}

使用,通过用户调用中介者方法实现业务功能,中介者负责实际业务功能

public class Main {
    public static void main(String[] args) {
        User user = new User("张三");
        User user01 = new User("李四");
        user.sendMessage("睡觉");
        user01.sendMessage("工作");
    }
}

责任链模式#

为请求创建一个接收者对象的链,对请求的发送者和接收者进行解耦

在这种模式中,通常每个接收者都包含另一个接受者的引用。如果一个对象不能处理该请求,那么它就会把相同的请求传给下一个接收者,以此类推。

避免请求者和请求者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成为一条链,并沿着这条链传递请求,直到有对象处理它为止。

职责链上的处理者负责处理请求,客户只需要将请求发送到责任链上即可,无需关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求处理器解耦了。

详细构思

这个部分我们后续的项目会用到,故好好学学

现在需要开发一个请假流程控制系统,请假一天以下只需要小组长同意即可,1-3天还需要部门经理同意,请求3-7天还需要总经理同意

/**
 * 请假条类
 */
@Data
public class LeaveRequest {
    private String name;
    private int day;
    private String content;
    public LeaveRequest(String name, int day, String content) {
        this.name = name;
        this.day = day;
        this.content = content;
    }
}
/**
 * 抽象处理者类
 */
public abstract class Handler {
    protected final static int NUM_ONE = 1;
    protected final static int NUM_THREE = 3;
    protected final static int NUM_SEVEN = 7;

    //该领导的处理天数区间
    private int numStart;
    private int numEnd;

    //声明后继者(上级领导)
    private Handler nextHandler;
    
    public Handler(int numStart, int numEnd) {
        this.numStart = numStart;
        this.numEnd = numEnd;
    }

    //设置上级领导对象
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    //各级领导处理请假条的方法
    protected abstract void handleLeave(LeaveRequest leave);

    //提交请假条
    public final void submit(LeaveRequest leave) {
        //先进行审批
        this.handleLeave(leave);
        if (leave.getDay() >= numStart && leave.getDay() <= this.numEnd) {
            System.out.println("流程成功");
        } else if (this.nextHandler != null) {
            this.nextHandler.handleLeave(leave);
        } else {
            System.out.println("流程失败");
        }
    }
}
/**
 * 小组长类
 */
public class GroupLeader extends Handler{
    public GroupLeader() {
        super(0, Handler.NUM_ONE);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getDay() + "天" + leave.getContent() + "请假原因");
        System.out.println("小组长审批,同意");
    }
}
public class Main {
    public static void main(String[] args) {
        LeaveRequest leave = new LeaveRequest("产假", 5, "回家修养");
        //创建各个节点处理
        GroupLeader group = new GroupLeader();
        Manager manager = new Manager();
        GeneralManage generalManage = new GeneralManage();

        //设置链
        group.setNextHandler(manager);
        group.setNextHandler(generalManage);
        group.submit(leave);
    }
}

这个设计模式在Filter链中也有使用,在进行处理的时候先进行前置处理,然后调用责任链的下一个处理器的处理,在结束后进行一开始的后置处理

访问者模式#

使用一个访问类,改变了元素类的执行算法

通过这种方式,元素的执行算法可以随着访问者改变而改变,这种类型的设计模式属于行为型模式

根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作

主要讲数据结构与数据操作分离,稳定的数据结构和易变的操作耦合问题

// Element 接口:所有元素必须实现 accept(Visitor)
interface DocumentElement {
    void accept(DocumentVisitor visitor);
}

// Visitor 接口:定义对不同元素的操作
interface DocumentVisitor {
    void visit(TextElement text);
    void visit(ImageElement image);
}
// 具体元素:文本
class TextElement implements DocumentElement {
    private String content;

    public TextElement(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this); // 调用访问者的 visit(TextElement)
    }
}

// 具体元素:图片
class ImageElement implements DocumentElement {
    private String src;

    public ImageElement(String src) {
        this.src = src;
    }

    public String getSrc() {
        return src;
    }

    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this); // 调用访问者的 visit(ImageElement)
    }
}
// 访问者1:导出HTML
class HtmlExportVisitor implements DocumentVisitor {
    @Override
    public void visit(TextElement text) {
        System.out.println("<p>" + text.getContent() + "</p>");
    }

    @Override
    public void visit(ImageElement image) {
        System.out.println("<img src=\"" + image.getSrc() + "\"/>");
    }
}

// 访问者2:统计字数
class WordCountVisitor implements DocumentVisitor {
    private int wordCount = 0;

    @Override
    public void visit(TextElement text) {
        wordCount += text.getContent().split(" ").length;
    }

    @Override
    public void visit(ImageElement image) {
        // 图片不参与字数统计
    }

    public int getWordCount() {
        return wordCount;
    }
}
class Document {
    private List<DocumentElement> elements = new ArrayList<>();

    public void addElement(DocumentElement element) {
        elements.add(element);
    }

    // 遍历所有元素,接受访问者操作
    public void accept(DocumentVisitor visitor) {
        for (DocumentElement element : elements) {
            element.accept(visitor);
        }
    }
}
public class Client {
    public static void main(String[] args) {
        Document document = new Document();
        document.addElement(new TextElement("Hello World"));
        document.addElement(new ImageElement("photo.jpg"));
        document.addElement(new TextElement("Visitor Pattern Example"));

        // 导出HTML
        System.out.println("HTML Export:");
        document.accept(new HtmlExportVisitor());

        // 统计字数
        WordCountVisitor wordCounter = new WordCountVisitor();
        document.accept(wordCounter);
        System.out.println("Word Count: " + wordCounter.getWordCount());
    }
}

状态模式#

在状态模式中,类的行为是基于它的状态改变的

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类

对象的行为依赖于它的属性,并且可以根据它的状态改变而改变它的相关行为

内容类

public class Context {
    private State state;
    public Context() {
        state = null;
    }

    public State getState() {
        return state;
    }

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

状态接口,其中传入Context类

public interface State {
    public void operator(Context context);
}

实现状态接口

public class StartState implements State {
    @Override
    public void operator(Context context) {
        System.out.println("开启");
        context.setState(this);
    }

    @Override
    public String toString() {
        return "正在进行...";
    }
}
public class StopState implements State {
    @Override
    public void operator(Context context) {
        context.setState(this);
    }

    @Override
    public String toString() {
        return "已结束...";
    }
}

调用

public class Main {
    public static void main(String[] args) {
        Context context = new Context();
        State start = new StartState();
        start.operator(context);
        System.out.println(start.toString());
        State stop = new StopState();
        stop.operator(context);
        System.out.println(stop.toString());
    }
}
设计模式笔记(行为型模式)
https://thrinisty.github.io/Blog/posts/设计模式笔记行为型模式/
作者
Thrinisty
发布于
2025-10-25
许可协议
CC BY-NC-SA 4.0