行为型模式

行为型模式

1. 模版方法模式

1.1 介绍

模版方法模式是一种行为设计模式,它在一个方法中定义了一个算法的骨架,但将一些步骤延迟到子类中。模版方法允许子类在不改变算法结构的情况下重新定义算法的某些步骤

1.2 结构

模板方法(Template Method)模式包含以下主要角色:

  • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成

    • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法

    • 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:

    • 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现

    • 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承

    • 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种

      一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型

  • 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤

1.3 实现

炒菜的步骤是固定的,分为倒油、热油、倒蔬菜、倒调料品、翻炒等步骤。现通过模板方法模式来用代码模拟。类图如下:

image-20230921091341644

  • 抽象类(Abstract Class):
public abstract class AbstractClass {

    public final void cookProcess() {
        //第一步:倒油
        this.pourOil();
        //第二步:热油
        this.heatOil();
        //第三步:倒蔬菜
        this.pourVegetable();
        //第四步:倒调味料
        this.pourSauce();
        //第五步:翻炒
        this.fry();
    }

    //第一步:倒油是一样的,所以直接实现
    public void pourOil() {
        System.out.println("倒油");
    }

    //第二步:热油是一样的,所以直接实现
    public void heatOil() {
        System.out.println("热油");
    }

    //第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)
    public abstract void pourVegetable();

    //第四步:倒调味料是不一样
    public abstract void pourSauce();

    //第五步:翻炒是一样的,所以直接实现
    public void fry() {
        System.out.println("炒啊炒啊炒到熟啊");
    }
}
  • 具体子类(Concrete Class):
public class ConcreteClass_BaoCai extends AbstractClass{
    @Override
    public void pourVegetable() {
        System.out.println("下锅的蔬菜是包菜");
    }

    @Override
    public void pourSauce() {
        System.out.println("下锅的酱料是辣椒");
    }
}

public class ConcreteClass_CaiXin extends AbstractClass{
    @Override
    public void pourVegetable() {
        System.out.println("下锅的蔬菜是菜心");
    }

    @Override
    public void pourSauce() {
        System.out.println("下锅的酱料是蒜蓉");
    }
}
  • 测试类:
public class Client {
    public static void main(String[] args) {
        // 炒手撕包菜
        ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();
        baoCai.cookProcess();

        //炒蒜蓉菜心
        ConcreteClass_CaiXin caiXin = new ConcreteClass_CaiXin();
        caiXin.cookProcess();
    }
}

注意:为防止恶意操作,一般模板方法都加上 final 关键词

1.4 优缺点

优点:

  1. 封装不变部分,扩展可变部分:模板方法模式可以将固定的部分封装起来,而将可变的部分留给子类来实现,这样可以提高代码的复用性
  2. 提取公共代码:通过模板方法模式,可以将公共的部分代码提取出来,使得代码更加整洁,便于维护
  3. 良好的封装性:模板方法模式可以将公有的部分代码封装起来,使得代码结构更加清晰

缺点:

  1. 算法框架的限制:部分客户端可能会受到算法框架的限制,这可能会影响到系统的灵活性
  2. 违反里氏替换原则:如果通过子类来抑制默认的步骤实现,可能会导致违反里氏替换原则
  3. 维护困难:如果模板方法中的步骤过多,其维护工作可能会变得更加困难

1.5 使用场景

模板方法设计模式的使用场景如下:

  1. 多个子类有共有的方法,并且逻辑基本相同:当多个子类中存在相似的方法和逻辑时,可以将这些共有的方法提取到一个抽象基类中,形成一个模板方法。子类只需实现与自身特定相关的部分
  2. 复杂的算法:对于一些重要且复杂的算法,可以将核心算法设计为模板方法,而将算法中的某些细节步骤留给子类来实现。这样,核心算法的结构不会因为子类的变化而变化
  3. 框架设计:在许多框架中,都会定义一些基本的模板方法,供用户或开发者根据具体需求进行细化实现。例如,Spring框架中的JdbcTemplateRestTemplateRabbitTemplateKafkaTemplate等都是模板方法模式的应用
  4. 防止恶意操作:在某些场景中,为了防止恶意操作或确保某些步骤的执行,可以使用模板方法模式来定义一个固定的执行流程,而将某些可变的步骤留给子类来实现

2. 策略模式

2.1 介绍

策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理

2.2 结构

策略模式的主要角色如下:

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境(Context)类:持有一个策略类的引用,最终给客户端调用

2.3 实现

一家百货公司在定年度的促销活动。针对不同的节日(春节、中秋节、圣诞节)推出不同的促销活动,由促销员将促销活动展示给客户。类图如下:

image-20230921101658386

  • 抽象策略(Strategy)类:
public interface Strategy {
    void show();
}
  • 具体策略(Concrete Strategy)类:
public class StrategyA implements Strategy{

    @Override
    public void show() {
        System.out.println("买一送一");
    }
}

public class StrategyB implements Strategy{

    @Override
    public void show() {
        System.out.println("满200元减50元");
    }
}

public class StrategyC implements Strategy{

    @Override
    public void show() {
        System.out.println("满1000元加一元换购任意200元以下商品");
    }
}
  • 环境(Context)类:
public class SalesMan {

    //持有抽象策略角色的引用
    private Strategy strategy;

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

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

    //向客户展示促销活动
    public void salesManShow() {
        strategy.show();
    }
}
  • 测试类:
public class Client {
    public static void main(String[] args) {
        SalesMan salesMan = new SalesMan(new StrategyA());
        salesMan.salesManShow();

        salesMan.setStrategy(new StrategyB());
        salesMan.salesManShow();

        salesMan.setStrategy(new StrategyC());
        salesMan.salesManShow();
    }
}

2.4 优缺点

优点

  1. 算法封装:策略模式提供了一种将算法封装在独立的策略类中的方法,使得它们可以相互替换
  2. 避免多重条件判断:策略模式避免了使用多重条件判断语句,使得代码更加清晰、易于维护
  3. 扩展性强:当需要增加新的算法或策略时,只需增加新的策略类即可,不需要修改原有的代码,符合开闭原则
  4. 客户端与策略解耦:客户端与策略算法解耦,客户端不需要知道策略的具体实现细节

缺点

  1. 策略数量增多:如果策略过多,会导致类的数量增加,可能会增加系统的复杂性
  2. 客户端选择策略:客户端需要知道所有的策略类,并根据具体情况选择合适的策略。如果策略选择不当,可能会导致系统效率降低或出现错误
  3. 公共功能问题:策略类可能会存在重复的代码,如果不进行适当的抽象和重构,可能会导致系统中存在冗余的代码

2.5 使用场景

策略模式的使用场景如下:

  1. 多种算法选择:当一个系统有多种算法可以选择,但每次只需要使用其中的一种时,可以使用策略模式。例如,排序算法中,我们可以选择冒泡排序、快速排序、归并排序等,通过策略模式可以轻松切换不同的排序算法
  2. 动态决策:在程序运行时,根据不同的情况选择不同的算法。例如,导航软件中,根据用户的选择(最短路径、避开高速、避开收费站等)来选择不同的路线规划策略
  3. 策略组合:当需要组合多种策略来得到某种结果时。例如,电商平台的促销策略,可能会组合多种策略如打折、满减、赠品等,通过策略模式可以灵活组合各种促销策略
  4. 替代多重条件判断:当代码中存在多重条件判断,且每个条件对应一个不同的行为或算法时,可以考虑使用策略模式。这样可以避免复杂的条件判断,使代码更加清晰和易于维护
  5. 策略配置和扩展:当系统中的某个行为需要频繁地进行配置、修改或扩展时,使用策略模式可以将这些变化的部分独立出来,使得主体代码不受影响

3. 责任链模式

3.1 介绍

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

3.2 结构

责任链模式主要包含以下角色:

  • 抽象处理者(Handler)类:定义一个处理请求的接口,通常包含抽象处理方法和一个指向下一个处理者的引用
  • 具体处理者(ConcreteHandler)类:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者
  • 客户(Client)类:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程

3.3 实现

现需要开发一个请假流程控制系统。请假一天以下的假只需要小组长同意即可;请假1天到3天的假还需要部门经理同意;请求3天到7天还需要总经理同意才行。类图如下:

image-20230921184413780

  • 请求类:
public class LeaveRequest {

    // 姓名
    private String name;

    // 请假天数
    private int num;

    //请假内容
    private String content;

    public LeaveRequest(String name, int num, String content) {
        this.name = name;
        this.num = num;
        this.content = content;
    }

    public String getName() {
        return name;
    }

    public int getNum() {
        return num;
    }

    public String getContent() {
        return content;
    }
}
  • 抽象处理者(Handler)类:
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) {
        this.numStart = numStart;
    }

    //设置请假天数范围
    public Handler(int numStart, int numEnd) {
        this.numStart = numStart;
        this.numEnd = numEnd;
    }

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

    //提交请假条
    public final void submit(LeaveRequest leave) {
        if (0 == this.numStart) {
            return;
        }

        //如果请假天数达到该领导者的处理要求
        if (leave.getNum() >= this.numStart) {
            this.handleLeave(leave);

            //如果还有上级 并且请假天数超过了当前领导的处理范围
            if (null != this.nextHandler && leave.getNum() > numEnd) {
                this.nextHandler.submit(leave);//继续提交
            } else {
                System.out.println("流程结束");
            }
        }
    }

    //各级领导处理请假条方法
    protected abstract void handleLeave(LeaveRequest leave);
}
  • 具体处理者(ConcreteHandler)类:
public class GroupLeader extends Handler {
    public GroupLeader() {
        //小组长处理1-3天的请假
        super(Handler.NUM_ONE, Handler.NUM_THREE);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("小组长审批:同意。");
    }
}

public class Manager extends Handler {
    public Manager() {
        //部门经理处理3-7天的请假
        super(Handler.NUM_THREE, Handler.NUM_SEVEN);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("部门经理审批:同意。");
    }
}

public class GeneralManager extends Handler {
    public GeneralManager() {
        //部门经理处理7天以上的请假
        super(Handler.NUM_SEVEN);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("总经理审批:同意。");
    }
}
  • 客户(Client)类:
public class Client {
    public static void main(String[] args) {
        //请假条
        LeaveRequest leave = new LeaveRequest("张三",8,"身体不适");

        //各位领导
        GroupLeader groupLeader = new GroupLeader();
        Manager manager = new Manager();
        GeneralManager generalManager = new GeneralManager();

        groupLeader.setNextHandler(manager);//小组长的领导是部门经理
        manager.setNextHandler(generalManager);//部门经理的领导是总经理
        //之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。

        //提交申请
        groupLeader.submit(leave);
    }
}

3.4 优缺点

优点:

  1. 解耦:请求的发送者和接收者(处理者)之间解耦,使得两者独立变化,增强了系统的灵活性
  2. 简化代码:通过责任链,可以避免硬编码请求的处理者,代码更加简洁和清晰
  3. 扩展性强:可以动态地添加或修改处理者,不影响其他的代码
  4. 灵活性:可以根据需要改变处理链,或者重新组织链中的处理者
  5. 分层处理请求:可以更容易地为请求定义多级处理机制,例如日志记录、权限检查、数据验证等

缺点:

  1. 性能问题:每个请求都从链的头部开始,直到链的尾部或被某个处理者处理。这可能会导致性能问题,特别是在链很长的情况下
  2. 不保证被处理:由于请求没有明确的接收者,所以不能保证它一定会被处理。如果没有任何处理者处理请求,它可能会到达链的尾部并被丢弃
  3. 调试和维护:由于处理者在运行时动态确定,所以可能会比较难以调试和维护
  4. 可能导致过多的对象:如果处理逻辑分散在许多小的处理者对象中,可能会导致系统中存在过多的对象

3.5 使用场景

责任链模式的使用场景如下:

  1. 动态处理请求:当系统需要根据不同的条件或规则动态处理请求时,责任链模式是有用的。例如,不同级别的日志记录器处理不同级别的日志消息
  2. 减少耦合:责任链模式有助于减少请求的发送者和接收者之间的耦合。发送者只需要知道链中的第一个接收者,而不需要知道链的结构和处理请求的具体对象
  3. 可扩展性:责任链模式允许在运行时动态地添加或移除处理者,这使得系统更加灵活,可以根据需要增加或减少处理者
  4. 处理多种类型的请求:当系统需要处理多种类型的请求,并且每种请求可能有不同的处理者时,责任链模式非常有用。例如,一个客户支持系统可能需要处理技术问题、账单问题和反馈,每种问题都有专门的处理者
  5. 避免硬编码处理者:在不使用责任链模式的情况下,请求的发送者可能需要硬编码所有可能的处理者。使用责任链模式,发送者只需要知道第一个处理者,而链的其他部分可以动态配置
  6. 分布式处理:责任链模式也可以用于分布式系统,其中请求的处理可能分布在不同的节点或服务器上。责任链模式允许请求在不同的节点之间传递,直到找到合适的处理者

4. 观察者模式

4.1 介绍

观察者模式(Observer pattern)是软件设计模式的一种,又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己

4.2 结构

在观察者模式中有如下角色:

  • 抽象主题(Subject)类:抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象
  • 具体主题(ConcreteSubject)类:该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知
  • 抽象观察者(Observer)类:是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己
  • 具体观察者(ConcrereObserver)类:实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态

4.3 实现

在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给关注公众号的微信用户端。我们使用观察者模式来模拟这样的场景,微信用户就是观察者,微信公众号是被观察者,有多个的微信用户关注了程序猿这个公众号。类图如下:

image-20230921104501675

  • 抽象观察者(Observer)类:
public interface Observer {
    void update(String message);
}
  • 具体观察者(ConcrereObserver)类:
public class WeixinUser implements Observer {

    // 微信用户名
    private String name;

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

    @Override
    public void update(String message) {
        System.out.println(name + "-" + message);
    }
}
  • 抽象主题(Subject)类:
public interface Subject {

    //增加订阅者
    void attach(Observer observer);

    //删除订阅者
    void detach(Observer observer);

    //通知订阅者更新消息
    void notify(String message);
}
  • 具体主题(ConcreteSubject)类:
public class ConcreteSubject implements Subject {

    //储存订阅公众号的微信用户
    private List<Observer> weiXinUserList = new ArrayList<Observer>();

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

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

    @Override
    public void notify(String message) {
        for (Observer observer : weiXinUserList) {
            observer.update(message);
        }
    }
}
  • 测试类:
public class Client {
    public static void main(String[] args) {

        ConcreteSubject concreteSubject = new ConcreteSubject();

        //创建微信用户
        WeixinUser user1 = new WeixinUser("孙悟空");
        WeixinUser user2 = new WeixinUser("猪悟能");
        WeixinUser user3 = new WeixinUser("沙悟净");

        //订阅公众号
        concreteSubject.attach(user1);
        concreteSubject.attach(user2);
        concreteSubject.attach(user3);

        //公众号更新发出消息给订阅的微信用户
        concreteSubject.notify("专栏更新了");
    }
}

4.4 优缺点

优点

  1. 解耦:观察者模式可以实现主题和观察者之间的解耦,使得它们之间的依赖关系变得松散,增加了系统的灵活性
  2. 动态关系:可以动态地添加或删除观察者,使得系统可以灵活地对观察者进行管理
  3. 广播通信:当主题对象的状态发生变化时,所有注册的观察者都会得到通知,实现了广播通信
  4. 支持抽象编程:主题和观察者都可以通过接口或抽象类来实现,不依赖于具体的类

缺点

  1. 开销问题:如果有大量的观察者,通知所有的观察者可能会花费大量的时间和资源
  2. 过度使用导致复杂性增加:如果过度使用观察者模式,可能会导致系统变得复杂难以维护
  3. 可能引起无限循环:在某些情况下,观察者和主题之间可能存在循环依赖,导致系统进入无限循环
  4. 需要注意隐式依赖:观察者模式中的依赖是隐式的,可能导致系统的修改和维护变得困难

4.5 使用场景

观察者模式的使用场景如下:

  1. 一对多依赖关系:观察者模式适用于存在一对多依赖关系的情况,其中一个对象(主题)的状态变化需要通知多个其他对象(观察者)
  2. 主题状态的改变需要通知观察者:当主题对象的状态发生变化并且希望通知观察者执行相应操作时,观察者模式是有用的。这种通知通常是通过回调或事件触发机制实现的
  3. 减少耦合:观察者模式有助于减少对象之间的耦合度,因为主题对象和观察者对象之间相互独立,不需要了解对方的详细实现
  4. 动态添加或移除观察者:观察者模式允许在运行时动态地添加或移除观察者,这使得系统更加灵活,可以根据需要增加或减少观察者
  5. 状态变化时通知多个对象:当一个对象的状态变化需要通知多个不同类型的对象时,观察者模式非常有用。例如,在一个图形编辑器中,形状的位置变化可能需要通知不同类型的工具栏、属性窗口和视图
  6. 支持分布式事件处理:观察者模式可用于分布式系统中,其中事件的产生和处理分布在不同的节点上。观察者模式允许节点在事件发生时异步通知其他节点

5. 命令模式

5.1 介绍

命令模式(Command Pattern)是一种行为设计模式,它将请求封装为一个对象,从而允许用户使用不同的请求、队列请求或记录请求日志,以及支持可撤销的操作。命令模式的核心思想是将操作和调用操作的对象解耦,使得调用者和接收者之间没有直接关系

5.2 结构

命令模式包含以下主要角色:

  • 抽象命令类(Command)类: 定义了执行操作的接口,通常只有一个名为 execute 的方法
  • 具体命令(ConcreteCommand)类:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作
  • 实现者/接收者(Receiver)类: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能
  • 调用者/请求者(Invoker)类: 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口

5.3 实现

餐厅中,顾客点餐,服务员把订单给厨师准备菜品的过程,就是一个命令模式。其中,服务员就是调用者角色,由它来发起命令;厨师就是接收者角色,真正命令执行的对象;命令中包含订单。类图如下:

image-20230921202114172

  • 订单类:
public class Order {

    // 餐桌号码
    private int diningTable;

    // 用来存储餐名并记录份数
    private Map<String, Integer> foodDic = new HashMap<>();

    public int getDiningTable() {
        return diningTable;
    }

    public void setDiningTable(int diningTable) {
        this.diningTable = diningTable;
    }

    public Map<String, Integer> getFoodDic() {
        return foodDic;
    }

    public void setFoodDic(String name, int num) {
        foodDic.put(name, num);
    }
}
  • 抽象命令类(Command)类:
public interface Command {
    void execute();
}
  • 实现者/接收者(Receiver)类:
public class SeniorChef {

    public void makeFood(int num, String foodName) {
        System.out.println(num + "份" + foodName);
    }
}
  • 具体命令(ConcreteCommand)类:
public class OrderCommand implements Command {

    //持有接受者对象
    private SeniorChef receiver;

    private Order order;

    public OrderCommand(SeniorChef receiver, Order order) {
        this.receiver = receiver;
        this.order = order;
    }

    public void execute() {
        System.out.println(order.getDiningTable() + "桌的订单:");
        Set<String> keys = order.getFoodDic().keySet();
        for (String key : keys) {
            receiver.makeFood(order.getFoodDic().get(key), key);
        }
        System.out.println(order.getDiningTable() + "桌的饭弄好了");
    }
}
  • 调用者/请求者(Invoker)类:
public class Waiter {

    //可以持有很多的命令对象
    private ArrayList<Command> commands;

    public Waiter() {
        commands = new ArrayList();
    }

    public void setCommand(Command cmd) {
        commands.add(cmd);
    }

    // 发出命令,厨师开始执行
    public void orderUp() {
        System.out.println("美女服务员:叮咚,大厨,新订单来了.......");
        for (int i = 0; i < commands.size(); i++) {
            Command cmd = commands.get(i);
            if (cmd != null) {
                cmd.execute();
            }
        }
    }
}
  • 测试类:
public class Client {
    public static void main(String[] args) {
        //创建2个order
        Order order1 = new Order();
        order1.setDiningTable(1);
        order1.getFoodDic().put("西红柿鸡蛋面", 1);
        order1.getFoodDic().put("小杯可乐", 2);

        Order order2 = new Order();
        order2.setDiningTable(3);
        order2.getFoodDic().put("尖椒肉丝盖饭", 1);
        order2.getFoodDic().put("小杯雪碧", 1);

        //创建接收者
        SeniorChef receiver = new SeniorChef();
        //将订单和接收者封装成命令对象
        OrderCommand cmd1 = new OrderCommand(receiver, order1);
        OrderCommand cmd2 = new OrderCommand(receiver, order2);
        //创建调用者 Waiter
        Waiter invoker = new Waiter();
        invoker.setCommand(cmd1);
        invoker.setCommand(cmd2);

        //将订单带到柜台 并向厨师喊 订单来了
        invoker.orderUp();
    }
}

5.4 优缺点

优点

  1. 解耦:命令模式能够将调用操作的对象与知道如何执行操作的对象解耦。这意味着调用者和接收者之间没有直接的依赖关系
  2. 扩展性:可以容易地添加新的命令,因为新增的命令不会影响到已有的代码
  3. 灵活性:命令可以作为参数传递,也可以被保存在其他对象中,还可以在需要的时候被调用
  4. 支持撤销和重做:命令模式提供了实现撤销和重做操作的机制。每个具体的命令类可以实现自己的撤销逻辑
  5. 支持宏命令:可以将多个命令组合成一个宏命令,即一系列的命令可以按照某种顺序执行
  6. 支持命令的延迟执行:命令可以被保存起来,等到某个特定的时刻再执行

缺点

  1. 命令数量可能增多:对于每一个具体的操作,都可能需要一个具体的命令类。如果有许多具体操作,那么会导致命令类的数量增多,增加系统的复杂性
  2. 增加了系统的抽象性:引入命令模式会增加系统中的抽象层和间接性,可能会使系统变得更加复杂

5.5 使用场景

命令模式的使用场景如下:

  1. 需要将请求调用者与请求接收者解耦的场合:当调用者和接收者需要独立变化时,使用命令模式可以将二者解耦,使得增加新的命令或更改现有命令变得更容易
  2. 支持撤销/重做操作:例如,文本编辑器中的撤销(Undo)和重做(Redo)功能就可以使用命令模式来实现。每次执行一个操作时,都将该操作封装为一个命令对象并存储起来,撤销操作时就执行该命令的反操作
  3. 需要支持宏命令的场合:宏命令是一系列命令的集合,通过命令模式,可以将多个命令组合成一个宏命令
🌟 如果您喜欢我的文章,欢迎赞赏支持,您的支持是我创作的最大动力!🌟
🖋 作者:Enndfp
🔗链接:https://blog.enndfp.cn
📜版权声明:您可以自由转载,但请务必注明原文地址,感谢您的尊重与支持~

评论

  1. Windows Chrome
    1 年前
    2023-11-07 22:28:16

    写的真不错

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇