设计模式(三)命令模式

今天在面试别人的过程,问到了设计模式,他说命令模式,what!!我没有听过,我只能强装淡定,问了问他,回来赶紧翻翻书,补一补。

命令模式

日常背书:命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。先来讲个故事吧,再来说说自己的理解。

板面的故事

板面相信大家都吃过吧,今天讲的是公司那边的一家板面店, 我们皮皮家族经常去吃,这家店中只有老板和老板娘,每次都记不住我们点了什么,也记不住点餐的顺序,经常发生的场景就是,老板端着一碗板面说兄弟的板面加肠好了,你满面黑线的说,我点的是盖饭。下面我们用代码来描述下这个板面的业务模型。

板面1.0:紧耦合

板面店:

package edu.design.pattern.command;

/**
 * @author ZhaoWeinan
 * @date 2018/3/21
 * @description
 */
public class Noodler {

    public void makeNoodle(){
        System.out.println("兄弟,你的板面加肠加蛋!");
    }

    public void makeRice(){
        System.out.println("兄弟,你的盖饭!");
    }
}

皮皮家族来到了板面店

package edu.design.pattern.command;

/**
 * @author ZhaoWeinan
 * @date 2018/3/21
 * @description
 */
public class Demo {

    public static void main(String[] args){
        Noodler noodler = new Noodler();
        //皮皮家族来到了板面店,点了3个板面,2个盖饭
        noodler.makeNoodle();
        noodler.makeRice();
        noodler.makeNoodle();
        noodler.makeRice();
        noodler.makeNoodle();
    }
}

效果:


板面1.0的效果

板面1.0,描述了目前板面店的业务模型,实现很简单,但是暴露了很多问题。

从现实业务上来看

我们作为消费者直接与厨师(做饭也是老板和老板娘做的)交互,他们无法专注于自己的本质工作(做饭),需要记住每个人点的东西,每个点餐的顺序,就造成了目前的情况,不是看你点了什么,而是看他们做了什么,你点的东西可能已经没有原材料做不了了,但是也无法及时通知你,你想换一种饭,他可能无法顾及你的需求,这种不单一的职责,让他们无法同时顾及做饭与招呼客人点东西,两边的工作都可能做不好

从代码上来看

这种设计,我们作为行为请求者,板面店作为行为执行者,两者是紧耦合,对于一些简单的场景,这么做比较合适,请求者直接与执行者交互,但在某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种紧耦合的设计就不是很合适

板面2.0:使用命令模式为板面店解耦

我们皮皮家族一直在讨论板面店的问题在,认为关键点就是把招呼客人与做饭分开,在我们的代码中,修改老板与老板娘的职责,让他们只负责做饭:

package edu.design.pattern.command;

/**
 * @author ZhaoWeinan
 * @date 2018/3/22
 * @description
 */
public class Maker {

    public void make(String s){
        System.out.println("兄弟,我只负责做饭!我正在" + s);
    }

    //老板、老板娘查看厨房信息,看看客人点的是否能做
    public boolean getInfo(String s){
        if ("板面".equals(s)){
            return true;
        }else if ("盖饭".equals(s)){
            return true;
        }else if ("韭菜水饺".equals(s)){
            System.out.println("韭菜没有了,不要让客人点韭菜水饺了!");
            return false;
        }else {
            return true;
        }
    }
}

为板面店做一个订单系统:

package edu.design.pattern.command;

/**
 * @author ZhaoWeinan
 * @date 2018/3/22
 * @description
 */
public interface Command {

    /**
     * 订单系统通知老板、老板娘做饭
     */
    void execute();

    /**
     * 获取厨房信息
     * @return
     */
    String getMakeInfo();
}

在订单系统中,添加一个板面的信息

package edu.design.pattern.command;

/**
 * @author ZhaoWeinan
 * @date 2018/3/22
 * @description
 */
public class NoodleCommand implements Command {

    private Maker maker;

    public NoodleCommand(Maker maker) {
        this.maker = maker;
    }

    @Override
    public void execute() {
        System.out.println("订单系统通知老板,做一碗板面!");
        maker.make("做板面");
    }

    @Override
    public String getMakeInfo() {
        if (maker.getInfo("板面")){
            System.out.println("老板查看厨房信息!");
            System.out.println("发现有材料,可以做板面!");
            System.out.println("通过订单系统,通知服务员招呼客人说:可以点板面!");
            return "老板,给做一碗板面!";
        }else {
            System.out.println("没有材料,做不了板面了!");
            return "NULL";
        }
    }
}

为板面店招聘一个服务员,专门负责招呼客人:

package edu.design.pattern.command;

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

/**
 * 服务员类
 * @author ZhaoWeinan
 * @date 2018/3/22
 * @description
 */
public class Waiter {

    //服务员控制订单系统
    private List<Command> commandList = new ArrayList<>();

    //服务员招呼客人,把客人的点餐情况输入点餐系统
    //今天没有韭菜了,韭菜水饺点不了了
    public void setCommand(Command command){
        if (command.getMakeInfo().equals("NULL")){
            System.out.println("韭菜没有了,包不了韭菜水饺了!");
        }else {
            commandList.add(command);
        }
    }

    //服务员在订单系统中通知老板、老板娘做饭
    public void notifyMaker(){
        if (commandList.size() == 0){
            System.out.println("暂时没有客人点餐!");
        }
        for (Command command : commandList){
            command.execute();
        }
    }
}

板面店重新开张,皮皮家族又来了:

package edu.design.pattern.command;

/**
 * @author ZhaoWeinan
 * @date 2018/3/22
 * @description
 */
public class CommandDemo {

    public static void main(String[] args){
        //老板登场
        Maker maker = new Maker();
        //服务员登场,招呼客人
        Waiter waiter = new Waiter();
        //服务员查看订单系统通知,是否可以点板面
        Command command = new NoodleCommand(maker);
        //服务员通过订单系统点了一份板面
        waiter.setCommand(command);
        //服务员点击确认,订单系统通知老板做饭
        waiter.notifyMaker();
    }
}

效果:


板面2.0的效果

通过这次板面2.0的升级,解决了1.0中的这些问题,板面的故事,讲完了,让我们来总结一下吧。

总结

从上面的故事我们来总结一下

需要解决的问题

行为请求者与执行者之间紧耦合的设计,对于一些简单的场景,这么做比较合适,请求者直接与执行者交互,但在某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种紧耦合的设计就不是很合适。

解决的方式

命令模式制定了三个主要的角色:命令执行对象receiver、 命令对象command、命令请求的入口invoker,通过请求者通过命令请求的入口把命令传递给接受执行者进行命令的执行,来把请求→执行的过程进行了解耦

优点

1、降低了系统耦合度
2、可以比较容易的把命令记入日志
3、允许命令接收方决定是否接受命令
4、新的命令可以很容易添加到系统中去

命令模式就为大家说到这里,欢迎大家来交流,指出文中一些说错的地方,让我加深认识。
谢谢大家!

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 9,353评论 3 14
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 12,405评论 2 17
  • 目录 本文的结构如下: 什么是命令模式 为什么要用该模式 模式的结构 代码示例 优点和缺点 适用环境 模式应用 总...
    w1992wishes阅读 4,860评论 2 9
  • 观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主体对象在状态发生变化时,会通...
    全栈未遂工程师阅读 2,812评论 0 1
  • 很轻松的坐在那里上班,发卡或者收钱。这是份细心的工作。在工作中我不断提醒自己要小心,细心。虽然简单且不断重复但是做...
    leayrainy阅读 937评论 0 1

友情链接更多精彩内容