首页 > 其他 > 详细

命令模式

时间:2019-07-06 10:55:48      阅读:79      评论:0      收藏:0      [点我收藏+]
Encapsulate a request as an object,thereby letting you parameterize clients with differentrequests,queue or log requests, and support undoable operations.

命令模式总不得要领。

做了3次迭代。

个人直觉,这个模式不会太常用,完全可以用数字或字符来代替命令, 解耦和简洁之间并非每次都是解耦胜出。

做菜这个场合,我站简洁。也可能网上例子都是做菜,所以才会让人觉得命令模式没有必要。应该是例子本来就不适合标准的命令模式。要不是 GOF他们4个人错了。

v1:简单的执行方法:waiter.BaoziCommand()

public class Command
{

    //Encapsulate a request as an object,thereby letting you parameterize clients with different
    //requests,queue or log requests, and support undoable operations.
    //将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能

    //命令模式很多目的,我们来实现其中一个简单的目的:记录请求。看看是否可以自行重构出命令模式。
    //1.首先用点菜来作为模拟场景。需要厨师来做菜,客人不能直接调用厨师的方法,所以需要一个服务员来作为客人和服务员的中介,这个是符合正常人思维并与现实吻合的。
    //第一版可以正常工作。可以看到唯一的不完美就是CommandInvoker中,创建命令的接受者没有符合开闭原则。
    //但是那个是工厂模式的事情。并且我们这里假设厨师是相对稳定的,不稳定的是客户的点餐,以致我们可以从适度设计的原则来抛弃使用工厂模式的想法。
    //2.实现记录命令功能,这里就是 某个常客说,来早餐,和昨天一样。 按道理很简单。存储一下啊。仔细看看BaoziCommand()。这个是方法没法储存。好吧开始迭代升级。
    public void Run()
    {
        String BreakFast="";
        CommandInvoker waiter=new CommandInvoker();
        BreakFast+= waiter.BaoziCommand();
        BreakFast+=waiter.EggCommand();
        BreakFast+=waiter.ChangFenCommand();
        LSComponentsHelper.LS_Log.Log_INFO(BreakFast);
    }

    //命令调用者(服务员):接受客户调用,并且最终去调用厨师的方法。
    public class CommandInvoker
    {
        private ICommandReceiver mBaozi=new BaoziTony();
        private ICommandReceiver mEgg=new EggXiaoZhang();
        private ICommandReceiver mChangfen=new ChangFenLaoWang();
        public String BaoziCommand()
        {
            return mBaozi.ExecuteCommand();
        }

        public String EggCommand()
        {
            return mEgg.ExecuteCommand();
        }

        public String ChangFenCommand()
        {
            return mChangfen.ExecuteCommand();
        }
    }

    //处理命令接口(抽象厨师)
    public interface ICommandReceiver
    {
        public String ExecuteCommand();
    }

    public class BaoziTony implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "BaoZi";
        }
    }
    public class EggXiaoZhang implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "Egg";
        }
    }
    public class ChangFenLaoWang implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "ChangFen";
        }
    }

}

 

v2:实现了命令和执行的简单解耦。

public class CommandV2
{
    //实现记录命令功能,这里就是 某个常客说,来早餐,和昨天一样。 按道理很简单。存储一下啊。仔细看看BaoziCommand()。这个是方法没法储存。好吧开始迭代升级。
    //很明显,发现我们使用最简迭代,达到了我们的目标,但是却不是标准的命令模式.先看看我们是否符合开闭原则。如果我们符合,那么肯定是写模式设计这本书的作者过度设计。
    //对于点餐来说,我们完全符合开闭原则。yesterdayList.add(EggCode);可以随便组合。非常灵活.那么可以肯定,一定是命令模式过度设计了。
    //ok,那我们也过度设计一下。假设菜品变动比较大。(基本不可能,所以命令模式在这里,确实是设计过度)
    //假设菜品变动比较大。yesterDayAgain,这个方法违背了开闭原则。

    private final Integer baoziCode=1;
    private final Integer EggCode=2;
    private final Integer ChangFenCode=3;
    public void Run()
    {
        String BreakFast="";
        CommandInvoker waiter=new CommandInvoker();
        BreakFast+= waiter.BaoziCommand();
        BreakFast+=waiter.EggCommand();
        BreakFast+=waiter.ChangFenCommand();
        LSComponentsHelper.LS_Log.Log_INFO(BreakFast);

        //把小胖崽的早餐记录下。
        List<Integer> yesterdayList=new ArrayList<>();
        yesterdayList.add(baoziCode);
        yesterdayList.add(EggCode);
        yesterdayList.add(ChangFenCode);
        waiter.mOrderHistory.put("fatBoy",yesterdayList );

        //第二天直接告诉老板:老板,早餐,照旧。
        LSComponentsHelper.LS_Log.Log_INFO(waiter.yesterDayAgain("fatBoy"));
    }

    //命令调用者(服务员):接受客户调用,并且最终去调用厨师的方法。
    public class CommandInvoker
    {
        private ICommandReceiver mBaozi=new BaoziTony();
        private ICommandReceiver mEgg=new EggXiaoZhang();
        private ICommandReceiver mChangfen=new ChangFenLaoWang();
        public Map<String,List<Integer>> mOrderHistory=new HashMap<String,List<Integer>>();
        public String BaoziCommand()
        {
            return mBaozi.ExecuteCommand();
        }

        public String EggCommand()
        {
            return mEgg.ExecuteCommand();
        }

        public String ChangFenCommand()
        {
            return mChangfen.ExecuteCommand();
        }
        public String yesterDayAgain(String guest)
        {
            String res="";
            List<Integer> commands=mOrderHistory.get(guest);
            for(Integer command:commands)
            {
                if(command==baoziCode)
                {
                    res+=(BaoziCommand());
                }
                else if(command==EggCode)
                {
                    res+=(EggCommand());
                }
                else if(command==ChangFenCode)
                {
                    res+=(ChangFenCommand());
                }
            }
            return res;
        }
    }


    //处理命令接口(抽象厨师)
    public interface ICommandReceiver
    {
        public String ExecuteCommand();
    }

    public class BaoziTony implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "BaoZiv2";
        }
    }
    public class EggXiaoZhang implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "Eggv2";
        }
    }
    public class ChangFenLaoWang implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "ChangFenv2";
        }
    }
}

 

v3,把命令封装成类。更面向对象,变成了标准的命令模式。 但是个人感觉没有  v2简洁。

public class CommandV3
{
    //假设菜品变动比较大。yesterDayAgain,这个方法违背了开闭原则。
    //我们应该可以让baoziCode,每个菜名,都会关联一个厨师的方法。这样通过属性和方法的结合,也就是类,达到开闭原则。
    //小结一下,对于常见的方法调用XXX.fun1().XXX.fun2(). 无法保存和组合方法顺序。所以最简方案。我们会用数字或字符1,2,3来代替方法xxx.fun1,fun2,fun3
    //但是稍微面向对象一点,我们可以把方法放入到某个类中,那么意思就是把方法的执行者也包进来。就是这么简单。
    //再回顾定义:Encapsulate a request as an object,没毛病,把方法放到类中,所以一并把方法的执行者也放到类中。完毕。
    //至于标准的uml图。我觉得invoker在这里是多余,命令类已经包含执行者。不需要invoker.
    //waiter.CheckAndExecuteCommand(BaoziCode) 和BaoziCode.OneReceiverWillDoIt 那个更简洁?
    //个人直觉,这个模式不会太常用,完全可以用数字或字符来代替命令, 解耦和简洁之间并非每次都是解耦胜出。这个场合,我站简洁。

    public void Run()
    {
        String BreakFast="";
        CommandInvoker waiter=new CommandInvoker();

        AbsCommand BaoziCode=new BaoziCommand();
        BreakFast+= waiter.CheckAndExecuteCommand(BaoziCode);
        AbsCommand EggCode=new EggCommand();
        BreakFast+= waiter.CheckAndExecuteCommand(EggCode);
        AbsCommand ChangFenCode=new ChangFenCommand();
        BreakFast+= waiter.CheckAndExecuteCommand(ChangFenCode);
        AbsCommand jianJiaoCode=new JianJiaoCommand();
        BreakFast+= waiter.CheckAndExecuteCommand(jianJiaoCode);

        LSComponentsHelper.LS_Log.Log_INFO(BreakFast);

        //把小胖崽的早餐记录下。
        List<AbsCommand> yesterdayList=new ArrayList<>();
        yesterdayList.add(BaoziCode);
        yesterdayList.add(EggCode);
        yesterdayList.add(ChangFenCode);
        yesterdayList.add(jianJiaoCode);
        waiter.mOrderHistory.put("fatBoy",yesterdayList );

        //第二天直接告诉老板:老板,早餐,照旧。
        LSComponentsHelper.LS_Log.Log_INFO(waiter.yesterDayAgain("fatBoy"));
    }

    //region command
    //抽象命令(抽象菜名)
    public interface AbsCommand
    {
        public String OneReceiverWillDoIt();
    }
    //命令的实现者(菜名和执行厨师类)
    public class BaoziCommand implements AbsCommand
    {
        private ICommandReceiver mCommandReceiver=new BaoziTony();
        @Override
        public String OneReceiverWillDoIt()
        {
            return mCommandReceiver.ExecuteCommand();
        }
    }
    public class EggCommand implements AbsCommand
    {
        private ICommandReceiver mCommandReceiver=new EggXiaoZhang();
        @Override
        public String OneReceiverWillDoIt()
        {
            return mCommandReceiver.ExecuteCommand();
        }
    }
    public class ChangFenCommand implements AbsCommand
    {
        private ICommandReceiver mCommandReceiver=new ChangFenLaoWang();
        @Override
        public String OneReceiverWillDoIt()
        {
            return mCommandReceiver.ExecuteCommand();
        }
    }
    //新加一个菜品:煎饺
    public class JianJiaoCommand implements AbsCommand
    {
        private ICommandReceiver mCommandReceiver=new JiaoJiaoLiu();
        @Override
        public String OneReceiverWillDoIt()
        {
            return mCommandReceiver.ExecuteCommand();
        }
    }
    //endregion

    //region Invoker
    //命令调用者(服务员):接受客户调用,并且最终去调用厨师的方法。
    public class CommandInvoker
    {
        public Map<String,List<AbsCommand>> mOrderHistory=new HashMap<String,List<AbsCommand>>();

        //还是需要Invoker来执行,因为可能需要更换command的Receiver(需要服务员来做决定,是否要更换厨师做某个菜。)
        public String CheckAndExecuteCommand(AbsCommand command)
        {
            return command.OneReceiverWillDoIt();
        }

        public String yesterDayAgain(String guest)
        {
            String res="";
            List<AbsCommand> commands=mOrderHistory.get(guest);
            for(AbsCommand command:commands)
            {
                res+=command.OneReceiverWillDoIt();
            }
            return res;
        }
    }
    //endregion

    //region Receiver
    //处理命令接口(抽象厨师)
    public interface ICommandReceiver
    {
        public String ExecuteCommand();
    }

    public class BaoziTony implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "BaoZiv2";
        }
    }
    public class EggXiaoZhang implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "Eggv2";
        }
    }
    public class ChangFenLaoWang implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "ChangFenv2";
        }
    }
    public class JiaoJiaoLiu implements ICommandReceiver
    {
        @Override
        public String ExecuteCommand()
        {
            return "jianjiaov2";
        }
    }
    //endregion
}

 

命令模式

原文:https://www.cnblogs.com/lsfv/p/11141884.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!