ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【设计模式】怒敲两百多行代码来解释命令模式!

2021-10-15 09:02:26  阅读:111  来源: 互联网

标签:代码 worker System 两百多 命令 println 设计模式 public out


什么是命令模式(Command)

概念

命令模式(Command Pattern)属于行为型模式,定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。命令模式讲究的是解耦合,可延迟,像线程就是命令模式的典例,如果不适用命令模式的话,那么就无法将我们要执行的方法交给线程去执行,必须立马执行方法。

举个例子,我们去餐厅吃饭,服务员都会拿个菜单给我们,这个菜单就是已经写好的“命令”,只需要我们跟服务员(请求者)说想要吃什么菜(命令),那服务员就会通知厨师(实现者)去做什么菜,我们觉得菜够了,也可以取消没有做的菜;还有电视机的遥控器,当我们想换台时,就拿起遥控器(请求者),按下其他台的按钮(命令),电视机(实现者)就会换台了,我们想退回去看直接点返回即可。

其实我也一直在想,这两个例子中“我们”是处于一个什么样的角色,“我们”是处于命令模式这个模块之外的角色,我们想实现需求就得去调用请求者,像点菜,你直接跟厨师说,厨师哪里会理你,还有你直接对电视机喊也没用。这里我们也可以体会到请求者是对命令如何使用做了封装,我们想使用只需要和请求者交互即可。

命令模式也非常像我们打开Windows或Linux的命令操作界面,我们只需要输入命令和参数,就可以执行功能了。

sudo_rm_rf

优点

  1. 降低系统的耦合度。通过引入命令这类对象,降低了请求者和实现者的耦合。
  2. 符合开放封闭原则。想要新增操作,只需要写新的命令类即可。
  3. 可以延迟执行、撤销,排队请求。

大部分的设计模式都是为了解耦合,高内聚,我写的都有点腻了。

缺点

  1. 增加了系统的复杂性。使用命令模式可能会使系统产生大量的命令类,每个操作都得去实现一个相应的命令类,大量的命令类会增加系统的复杂性。
  2. 降低了代码的可读性。使用命令模式是通过命令的方式把请求者和实现者分离开来,这不仅带来了代码设计上的困难,也增加了系统的理解难度。

大部分的设计模式都是存在一定的实现难度和增加系统的复杂性。

原则

“+”代表遵守,“-”代表不遵守或者不相关

原则开放封闭单一职责迪米特里氏替换依赖倒置接口隔离合成复用
++--+--

适用场景

  1. 基于事件驱动的模块。像浏览器的按钮、操作系统的控制台,都是一个动作或者一行命令触发就要去完成相应的操作。
  2. 要求请求者和实现者解耦。请求者和实现者不直接进行交互。
  3. 存在可以延迟执行、撤销、回滚等情况。像记录日志、保存信息到数据库这些。

如何实现

想要实现命令模式,需要以下四样东西:

  1. 抽象命令接口:用来声明命令,拥有执行命令的抽象方法 execute()。
  2. 具体命令类:实现抽象命令接口,并调用实现者完成功能。
  3. 实现者/接收者类:为具体命令类提供服务。
  4. 请求者/调用者类:命令的调用者,负责管理和执行命令。

上类图

这里我复制其他网站看到的命令模式的类图。大家可以看看了解一下,然后再去看我写的代码。

命令模式类图

上例子

夏天来了,家家户户都装了空调,现有一家安装空调以及维修空调的公司,这公司的领导负责给工人安排安装装和维修空调工作,工人接收到工作后就去安装和维修。

只想边吹空调边搞钱

类图:

image-20210604231156751

代码:

/**
 * Created on 2021/6/4.
 *
 * @author xuxiaobai
 */
public class CommandTest {
    public static void main(String[] args) {
        //领导
        Leader leader=new Leader();
        //只有张三一个工人
        Worker worker = new Worker("张三");
        System.out.println("领导安排工作");
        leader.addPlan(new InstallWork("A镇58号", worker));
        leader.addPlan(new RepairWork("B镇23号", worker));
        //哎,领导取消安排了
        leader.cancel();
        //重新安排
        leader.addPlan(new InstallWork("C镇15号", worker));
        leader.addPlan(new InstallWork("D镇8号", worker));
        leader.addPlan(new InstallWork("E镇6号", worker));

        System.out.println("领导下达命令");
        leader.order();
        /**
         * 结果:
         * 领导安排工作
         * 取消工作安排
         * 领导下达命令
         * 张三骑上了心爱的面包车,到达了C镇15号
         * 张三开始工作了
         * 卸下空调
         * 装内机
         * 装外机
         * 检验
         * 完成收工
         * 张三骑上了心爱的面包车,到达了D镇8号
         * 张三开始工作了
         * 卸下空调
         * 装内机
         * 装外机
         * 检验
         * 完成收工
         * 张三骑上了心爱的面包车,到达了E镇6号
         * 张三开始工作了
         * 卸下空调
         * 装内机
         * 装外机
         * 检验
         * 完成收工
         */
    }
}


/**
 * 实现者/接收者类
 * 工人类
 * 功能:到达目的地、装空调、修空调
 */
class Worker{

    private String name;
    //是否携带空调
    private boolean airConditioner=false;

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

    /**
     * 到达目的地
     * @param address
     */
    public void arrive(String address){
        System.out.print(name+"骑上了心爱的面包车,到达了");
        System.out.println(address);
    }

    /**
     * 带上空调
     */
    public void getAirConditioner(){
        this.airConditioner=true;
    }

    /**
     * 放下空调
     */
    private void putAirConditioner(){
        this.airConditioner=false;
    }

    /**
     * 装空调
     */
    public void installAirConditioner(){
        System.out.println(name+"开始工作了");
        System.out.println("卸下空调");
        putAirConditioner();
        System.out.println("装内机");
        System.out.println("装外机");
        System.out.println("检验");
        System.out.println("完成收工");
    }


    /**
     * 修空调
     */
    public void repairAirConditioner(){
        System.out.println(name+"开始工作了");
        System.out.println("拆外机壳");
        System.out.println("检查");
        System.out.println("拆内机壳");
        System.out.println("检查");
        System.out.println("维修");
        System.out.println("完成收工");
    }


}

/**
 * 抽象命令接口
 * 这里只能用接口,所以就用接口了,如果你想写个例子可以考虑写个抽象类
 * 工作类
 */
interface Work{
    void execute();
}

/**
 * 具体命令类
 * 装空调
 */
class InstallWork implements Work{
    //地址
    private String address;
    //工人
    private Worker worker;
    //领空调凭证
    private boolean voucher=false;

    public InstallWork(String address,Worker worker){
        this.address=address;
        this.worker=worker;
        this.voucher=true;
    }


    @Override
    public void execute() {
        if (voucher){
            //有凭证才能取空调
            worker.getAirConditioner();
        }else {
            System.out.println("没有取空调凭证,拿不到空调");
            return;
        }
        worker.arrive(address);
        worker.installAirConditioner();
    }
}

/**
 * 具体命令类
 * 修空调
 */
class RepairWork implements Work{
    //地址
    private String address;
    //工人
    private Worker worker;

    public RepairWork(String address,Worker worker){
        this.address=address;
        this.worker=worker;
    }


    @Override
    public void execute() {
        worker.arrive(address);
        worker.repairAirConditioner();
    }
}

/**
 * 空调公司领导
 */
class Leader{
    List<Work> works=new ArrayList<>();

    /**
     * 增加工作安排
     * @param work
     */
    public void addPlan(Work work){
        works.add(work);
    }

    /**
     * 下发工作
     */
    public void order(){
        Iterator<Work> iterator = works.iterator();
        while (iterator.hasNext()){
            Work work = iterator.next();
            work.execute();
            iterator.remove();
        }
    }

    /**
     * 取消安排
     */
    public void cancel(){
        System.out.println("取消工作安排");
        works.clear();
    }

}


大家简单看一下,理一下思路就可以了。

如果是不使用命令模式的话,那么就得我们直接操作Worker对象了,什么步骤都要我们来操作,而且不能够延时执行。使用了命令模式,我们甚至可以使用工厂来创建命令类,这样使用起来就更加地简便了。

总结

命令模式的关键在于它把请求/操作封装成一个命令对象,这些命令对象都是提前写好的,然后把这些命令交给实现者去完成操作,在命令没有执行之前可以撤销、新增命令。

我在学习命令模式的时候,就一直在想命令模式跟写方法有什么区别?直接写方法也是封装操作逻辑,但这样的话就不能延迟执行、撤销和回滚。

标签:代码,worker,System,两百多,命令,println,设计模式,public,out
来源: https://blog.csdn.net/weixin_45865724/article/details/120589246

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有