设计模式第四讲-命令模式

栏目: 后端 · 发布时间: 6年前

内容简介:今天我们介绍又一个行为模式《命令模式》.将一个请求封装为一个对象,从而使你可用不同的请求对客户端参数化;对请求排队或记录请求日志,以及支持可撤销的操作.命令模式最初来源于图形化用户界面设计,但现在广泛应用于企业应用设计,特别促进了控制器(请求和分发处理)和领域模型(应用逻辑)的分离.说的更简单一点,命令模式有助于系统更好的进行组织,并易于拓展。

今天我们介绍又一个行为模式《命令模式》.

将一个请求封装为一个对象,从而使你可用不同的请求对客户端参数化;对请求排队或记录请求日志,以及支持可撤销的操作.

命令模式最初来源于图形化用户界面设计,但现在广泛应用于企业应用设计,特别促进了控制器(请求和分发处理)和领域模型(应用逻辑)的分离.说的更简单一点,命令模式有助于系统更好的进行组织,并易于拓展。

模式共包含: 请求者(INVOKER)、接收者(RECEIVER)、命令(COMMAND)接口、 具体命令(CONCRETE COMMAND)

场景设置

如果您在做点餐 工具 的研发,如何设计这个点餐系统呢(传统型餐厅)

涉及角色 职责
顾客 点餐、用餐、买单
服务员 下单
厨房 接单、成单

第一版本实现

我们看下order类实现

package design.pattern;

import java.util.Map;

public class Order {


    private Map<String, Object> params = null;

    public Order(Map<String, Object> params) {
        this.params = params;
    }

    /**
     * 创建订单
     */
    public void createOrder() {
        System.out.println("桌号" + params.get("桌号") + "创建订单");
    }

    /**
     * 生产订单
     */
    public void orderUp() {
        stirFryUp();
        stapleFoodUp();
    }

    /**
     * 炒菜组
     */
    private void stirFryUp() {
        Object stirFryUp = this.params.get("炒菜");
        if (stirFryUp != null) {
            for (Object val : (Object[]) stirFryUp) {
                System.out.println("生产炒菜:" + val);
            }
        }

    }

    /**
     * 主食组
     */
    private void stapleFoodUp() {
        Object stapleFood = this.params.get("主食");
        if (stapleFood != null) {
            for (Object val : (Object[]) stapleFood) {
                System.out.println("生产主食:" + val);
            }
        }
    }

}
复制代码

我们看到这个类实现了订单创建到菜品输出

调用者:

String[] stirFry = {"鱼香肉丝", "茄子"};
        String[] stapleFood = {"米饭"};

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("桌号", 88);
        params.put("炒菜", stirFry);
        params.put("主食", stapleFood);

        Order order = new Order(params);
        //提交菜单
        order.createOrder();

        //生产菜单
        order.orderUp();
复制代码

从点单到提交菜单 生产菜单流程

output:

桌号88创建订单
生产炒菜:鱼香肉丝
生产炒菜:茄子
生产主食:米饭
复制代码

如果对于简单的需求来说,这个还是更加简单清晰的. 但是如果我们拓展更多的种类菜品,可能对于我们的类来说会越来越复杂.

我们用命令模式实现下

命令模式实现

  • Receiver接受者角色:该角色就是干活的角色,命令传递到这里是应该被执行的
  • Command命令角色:需要执行的所有命令都在这里声明
  • Invoker调用者角色:接收到命令,并执行命令

具体工作流程图:

设计模式第四讲-命令模式

Receiver接受者角色(具体执行任务者)

package design.pattern.Receiver;

public abstract class Receiver {
    public abstract void doSomething();
}

复制代码

炒菜具体工作实现

package design.pattern.Receiver;

/**
 * 炒菜组
 */
public class StirFryUpReceiver extends Receiver {

    private String[] menuList;

    public StirFryUpReceiver(String[] menuList) {
        this.menuList = menuList;
    }

    public void doSomething() {
        for (String v : menuList) {
            System.out.println("生产炒菜" + v);
        }
    }
}
复制代码

主食组具体实现

package design.pattern.Receiver;

public class StapleFoodUpReceiver extends Receiver {

    private String[] menuList;

    public StapleFoodUpReceiver(String[] menuList) {
        this.menuList = menuList;
    }

    public void doSomething() {
        for (String v : menuList) {
            System.out.println("生产主食" + v);
        }
    }
}

复制代码

Command命令角色(具体调用具体任务执行者,相当于饭店的柜台)

package design.pattern.Command;

/**
 * 命令抽象类
 */
public abstract class Command {
    abstract public void execute();
}
复制代码

炒菜组命令接收类

package design.pattern.Command;

import design.pattern.Receiver.Receiver;

/**
 * 炒菜组Command
 */
public class StirFryUpCommand extends Command {

    private Receiver receiver;

    /**
     * 设置真正的处理者
     *
     * @param
     */
    public StirFryUpCommand(Receiver _receiver) {
        this.receiver = _receiver;
    }

    /**
     * 生产菜单
     */
    public void execute() {

        //对于炒菜设置其他事项
        //todo

        receiver.doSomething();
    }
}
复制代码

主食组命令接收类

package design.pattern.Command;

import design.pattern.Receiver.Receiver;

/**
 * 主食组Command
 */
public class StapleFoodUpCommand extends Command {

    private Receiver receiver;

    /**
     * 设置真正的处理者
     *
     * @param
     */
    public StapleFoodUpCommand(Receiver _receiver) {
        this.receiver = _receiver;
    }

    /**
     * 生产菜单
     */
    public void execute() {
        receiver.doSomething();
    }
}

复制代码

为什么要有命令类存在,直接调用实现不就可以了么.原因在于更加的灵活性,针对不同的实现,我们还可以在execute中完成不同任务的其他和具体炒菜、主食功能无关的相应操作.增强了功能实现的灵活性

命令调用者(服务员实现类,此类还可以实现在生产前取消命令)

package design.pattern;

import design.pattern.Command.Command;

import java.util.ArrayList;

/**
 * 服务员
 */
public class Waiter {

    private ArrayList<Command> commands =  new ArrayList<>();

    public void addCommand(Command _command) {
        this.commands.add(_command);
    }

    public void production() {
        for (Command command : commands) {
            command.execute();
        }
    }
}
复制代码

这里我们使用了集合,目的在于我们可以添加命令,在执行production之前,还可以撤销命令。

客户端调用

String[] stirFry = {"鱼香肉丝", "茄子"};
String[] stapleFood = {"米饭"};

//炒菜小组
//命令具体实现者
StirFryUpReceiver stirFryUpReceiver = new StirFryUpReceiver(stirFry);
//命令绑定
StirFryUpCommand stirFryUpCommand = new StirFryUpCommand(stirFryUpReceiver);

//加份米饭
StapleFoodUpReceiver stapleFoodUpReceiver = new StapleFoodUpReceiver(stapleFood);
StapleFoodUpCommand stapleFoodUpCommand = new StapleFoodUpCommand(stapleFoodUpReceiver);

//服务员
Waiter waiter = new Waiter();
waiter.addCommand(stirFryUpCommand);
waiter.addCommand(stapleFoodUpCommand);
waiter.production();
复制代码

客户端代码执行步骤:

  1. 将具体菜单内容传递给执行者(厨师)
  2. 将此执行者对象绑定到Command(柜台)中
  3. 服务员类添加命令
  4. 服务员执行下单,调用production()开始生产

output:

生产炒菜鱼香肉丝
生产炒菜茄子
生产主食米饭
复制代码

关系图:

目录结构:

设计模式第四讲-命令模式

订单柜台模型

设计模式第四讲-命令模式

厨房类模型

设计模式第四讲-命令模式

服务员类

设计模式第四讲-命令模式

UML图

设计模式第四讲-命令模式

此图来源于网络, Invoker相当于我们的服务员类

疑问探讨:

问:接收者一定要存在吗,为什么命令对象不直接实现execute方法的细节?

答:上面已经回答了 “为什么要有命令类存在” 的问题, 核心还是看实际业务,主要在于项目复杂度和解耦的程度.

注意: 不是确定要用使用,最好不要在项目使用此模式,更多建议在优化阶段使用。

工作中大部分直接实现了请求,而不是像我们将工作委托给了接受者(Command->Receiver)

更多精彩内容,关注公众号:

设计模式第四讲-命令模式

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Natural Language Processing with Python

Natural Language Processing with Python

Steven Bird、Ewan Klein、Edward Loper / O'Reilly Media / 2009-7-10 / USD 44.99

This book offers a highly accessible introduction to Natural Language Processing, the field that underpins a variety of language technologies, ranging from predictive text and email filtering to autom......一起来看看 《Natural Language Processing with Python》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具