• 命令模式(基本了解的程度)


    第二次复习
    1.感觉命令模式最大的特点是 包含一个执行者。
    所以如果是做撤销动作,组合动作,那么就会容易推导出命令模式。
    2.另外为了解耦,命令对象一般还需要 一个invoker调用者,这样客户就不必知道命令的细节了。只需要知道invoker就可以了。



    第一次学习
    Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests, and support undoable operations.

    命令模式总不得要领。

    做了3次迭代。

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

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

    而且,如果要真正的符合开闭原则,client 不应该可以直接接触到command, 因为command 里面包含一个 receiver。什么鬼?客户端只想发送一个指令,但是这个指令,却包含了一个执行者,完全没有解耦。(再看一次,发现是自己没有完整实现命令模式,完整的模式包含一个invoker. 来组合command和receiver。client只接触invoker.虽然错误理解了模式,但是却发现了正确模式,也算理解开闭原则。)

    command 模式还必须再加一层。让client 只接触指令。而这个指令不能包含Reiceiver。有空在实践一次。

    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
    }
  • 相关阅读:
    派生类的构造函数
    继承和派生
    自增自减运算符的重载(强制类型转换运算符重载)
    流插入和流提取运算符的重载
    动态数组类的设计
    函数的返回值
    赋值运算符的重载
    运算符重载
    常量对象函数引用和参数传递
    理解ASP.NET MVC的路由系统
  • 原文地址:https://www.cnblogs.com/lsfv/p/11141884.html
Copyright © 2020-2023  润新知