美文网首页
命令模式

命令模式

作者: 第八区 | 来源:发表于2017-09-13 17:36 被阅读10次

    元素

    • 抽象命令/具体命令
    • 抽象接受者/具体接受者
    • 调用者
    • 客户端
    command_url.png

    应用场景举例

    这里我们用一个场景来描述:去川湘阁饭店点一份剁椒鱼头和宫保鸡丁。
    这里我们把整个关键流程写出来

    • 点菜下单
    • 收银台出单
    • 厨房收到抄菜单,分给具体厨师
    • 厨师炒菜

    接下来我们就可以抽象出具体的角色。客户端当然就是我们的用户,调用者就是收银台出单的妹纸,命令就是抄菜单,接受者就是厨师。这样就很清晰了,客户端(用户)不需要知道功能(炒菜)怎么实现或者谁实现,他只需要找调用者(服务员/前台)描述清楚,然后调用者发命令给接受者(厨师),然后接受者执行命令(炒菜)。 这个流程非常的清晰也不会出错。什么样的命令给什么样的接受者执行,比如:剁椒鱼头,就打剁椒鱼头的票,然后指定给会做剁椒鱼头的师傅做。宫保鸡丁就给会做宫保鸡丁的师傅做。这个过程中,命令(小票)包含接受者(师傅)的信息。不同的命令对应不同的接受者。所以这里建立命令和接受者的抽象。

    优点

    • 将请求的发起者和执行者接口,通过命令来实现,将客户端的调用参数化。只需要将每个动作封装正命令,由发起者命令执行者来执行
    • 请求排队、记录每个请求。拿上面的场景来说,当很多客人点了剁椒鱼头时,厨师可能做不过来,这时候就得排队,先来的先做。

    示例(C++版):

    接受者(厨师)抽象类
    #include<iostream>
    using namespace std;
    class Chef
    {
    public:
        virtual int cooking(int id)=0;
        virtual void printTicketIds()const = 0;
        virtual ~Chef() {}
    };
    
    具体接受者(川湘阁做剁椒鱼头的厨师)类
    #include "Chef.h"
    class FishChef :
        public Chef
    {
        int id;
        string name;
        deque<int> ticketIds;
    public:
        FishChef(int id, string name);
        int cooking(int id);
        void printTicketIds()const;
        ~FishChef();
    };
    
    #include "FishChef.h"
    
    
    FishChef::FishChef(int id, string name)
    {
        this->id = id;
        this->name = name;
    }
    
    
    FishChef::~FishChef()
    {
    }
    
    void FishChef::printTicketIds()const {
        cout << "id为" << this->id << "  姓名为:" << this->name.c_str() << "的厨师需要做的菜";
        for (deque<int>::const_iterator it = ticketIds.begin(); it != ticketIds.end(); it++) {
            cout << *it << " ";
        }
        cout << endl;
    }
    
    int FishChef::cooking(int id) {
        if (ticketIds.size() > 3) {
            return 1;
        }
        ticketIds.push_back(id);
        return 0;
    }
    
    抽象命令(炒菜单)
    #include<iostream>
    #include "Chef.h"
    using namespace std;
    class Order
    {
    protected :
        Chef* chef;
    public:
        Order(Chef* chef) {
            this->chef = chef;
        }
        virtual void make()=0;
        ~Order() {
            if (chef != NULL)
                delete chef;
        }
    };
    
    具体命令(川湘阁的抄菜单)
    #include "stdafx.h"
    #include "ChuangXiangGeOrder.h"
    
    ChuangXiangGeOrder::ChuangXiangGeOrder(Chef * chef, int id):Order(chef)
    {
        this->id = id;
    }
    
    void ChuangXiangGeOrder::make()
    {
        if (chef == NULL) {
            cout << "请先设置厨师" << endl;
        }
        int res = chef->cooking(id);
    }
    
    ChuangXiangGeOrder::~ChuangXiangGeOrder()
    {
    }
    
    抽象调用者(下单服务员)
    #include<iostream>
    #include<vector>
    #include<string>
    #include"Order.h"
    using namespace std;
    using namespace std;
    class Waiter
    {
    protected:
        Order* order;
    public:
        Waiter() {}
        virtual pair<int,string> setOrder(Order* order)=0;
        virtual void execute()=0;
        ~Waiter() {}
    };
    
    具体调用者(川湘阁的下单服务员)
    #include "stdafx.h"
    #include "ChuanXiangGeWaiter.h"
    
    ChuanXiangGeWaiter::ChuanXiangGeWaiter()
    {
    }
    
    pair<int, string> ChuanXiangGeWaiter::setOrder(Order* order)
    {
        Waiter::order = order;
        return pair<int, string>();
    }
    
    void ChuanXiangGeWaiter::execute()
    {
        if (order == NULL) {
            cout << "请先下单" << endl;
        }
        order->make();
    }
    
    
    ChuanXiangGeWaiter::~ChuanXiangGeWaiter()
    {
        
    }
    
    测试代码
    int main()
    {
        Chef *chef = new FishChef(1, "张厨师");
        Order *order = new ChuangXiangGeOrder(chef,1001);
        Waiter *waiter = new ChuanXiangGeWaiter();
        waiter->setOrder(order);
        waiter->execute();
        chef->printTicketIds();
    
        Order *order1 = new ChuangXiangGeOrder(chef, 1002);
        waiter->setOrder(order1);
        waiter->execute();
        chef->printTicketIds();
    
        Order *order2 = new ChuangXiangGeOrder(chef, 1003);
        waiter->setOrder(order2);
        waiter->execute();
        chef->printTicketIds();
        return 0;
    }
    

    结果:

    command.png

    java版

    线程池
    Executor就是抽象调用者

    public interface Executor {
    
        /**
         * Executes the given command at some time in the future.  The command
         * may execute in a new thread, in a pooled thread, or in the calling
         * thread, at the discretion of the {@code Executor} implementation.
         *
         * @param command the runnable task
         * @throws RejectedExecutionException if this task cannot be
         * accepted for execution
         * @throws NullPointerException if command is null
         */
        void execute(Runnable command);
    }
    

    我们看到其中一个实现类ThreadPoolExecutor


    图片来自官方api文档

    看到Executor的源码,我们看到参数的起名都是command。这里Runable就是抽象的命令。那接受者呢。其实这里的接受者也是Runable。同时ThreadPoolExecutor除了能够发起命令外,还可以对Runable进行排队。这里我们用一个例子说明

    测试
    public class TestMain {
        public static void main(String[] args) {
            new Thread(new TaskA(1)).start();
            ExecutorService executor = Executors.newFixedThreadPool(2);
            executor.execute(new TaskA(2));
            executor.execute(new TaskA(3));
            executor.execute(new TaskA(4));
        }
    
        static class TaskA implements Runnable {
            private int id;
    
            public TaskA(int id) {
                this.id = id;
            }
    
            public void run() {
                log(id+" TaskA begin");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log(id+" TaskA end");
            }
        }
        public static void log(String content) {
            System.out.println(content);
        }
    }
    

    结果

    1 TaskA begin
    2 TaskA begin
    3 TaskA begin
    1 TaskA end
    3 TaskA end
    2 TaskA end
    4 TaskA begin
    4 TaskA end
    

    相关文章

      网友评论

          本文标题:命令模式

          本文链接:https://www.haomeiwen.com/subject/rjrlsxtx.html