zoukankan      html  css  js  c++  java
  • 3.4 命令模式(5.2)


    1. 引子

    假定电视机/TV有方法open()、close()和changeChannel()用于打开、关闭和切换电视频道,而遥控器/Controller对TV的操作,通常使用消息传递/方法调用表达式。

    package method.command;
    /**
     * @author yqj2065
     * @version 0.1
     */
    public class Controller1{
        public static void foo(){
    		TV tv = new TV();
    		tv.open();
    		tv.changeChannel();
    		tv.close();
    	}
    }
    面向对象中的服务请求,或者说消息传递表达式如 
    tv.open();
    与命令式语言如C的函数调用的最大不同,是消息传递表达式包括消息接收者tv,另外再加上open()。

    图3-3 消息传递、C/S结构

    命令模式则是追求一种千秋万代一统江湖的服务请求方式。

    •  Controller不愿意记住方法名。open()、close()、changeChannel()这些东西?以后有没有很多其它的方法能够调用,或者说很多其它的服务能够请求呢?所以,我不愿意被方法名限制,我以exe ()作为普适的方法名,exe()被“方法对象化”为Command——使用Command封装exe ()。
    • Controller不愿意知道消息接收者是谁。司令员下命令打下这个山头,他会不会考虑要那个连长去带人攻打呢。管你谁谁,打下这个山头才是司令员关心的。

     学习命令模式稍有难度,毕竟一统江湖的事情,总得有点难度。

    package method.command;
    public interface Command{
    	public void exe();
    }
    

    以下,是直接给出命令模式,让大家死记硬背地理解呢?还是从0開始,研究一下Controller怎样才可以忘记/无视消息接收者及其被调方法名

    2. 命令与运行

    先直接给出命令模式的样例吧。

    既然有了Command,依照多态也好,难度系数为0的策略模式也罢,tv的open()演变成Command的子类OpenCommand

    OpenCommand有私有成员TV tv,而OpenCommand的exe()干什么?显然仅仅须要一条语句tv.open()。代码自己随手写吧。

    由于我们拥有依赖注入工具tool.God,(注意:在我的博客的非常多的文章中,都使用了该工具,可是类名用过FromPropertyFile、IoC、God,所在包也有所变化,懒得逐一改动相关博文了。代码的意思非常清楚,读者自己相应改动一下),因而代码

    package method.command; 
    import tool.God;
    public class Controller{
    	public static void test()	{
    	    Command c1 = (Command)God.create("open");
    	    c1.exe();
    	}
    }
    Controller只知道Command对象,Controller下的命令为字符串"open",God依据字符串"open"创建method.command.OpenCommand对象。

    忽略一切细节,Controller仅依赖Command,对比的,Controller1依赖TV,和TV的现有操作/方法名


    命令模式的基本结构

    ①命令模式的核心,是封装普适方法exe ()的Command。通过它及其子类,将如图3-3所看到的的通常的服务请求中的请求发送者和接收者全然解耦,或者说将通常的C/S结构的C与S解耦。

    C只依赖于Command。而OpenCommand依赖于Command和S。

    所以,我们经常说Command採用了命令模式。也许应该说 以Command同志为核心的命令模式?

    ②依赖于Command的各种类(不包含其子类),在《设计模式》中称为调用者(Invoker),它们是命令的发出者。借助反射机制或依赖注入模式或依赖注入工具类tool.God,调用者能够发出Command的各种子类封装的命令,并且不须要知道终于调用的是什么方法名、不须要知道终于谁运行。
    假设调用者突发奇想地发出(须要)新的命令,能够编写Command的新子类以及运行者。

    package method.command;
    public class EatCommand implements Command{
        @Override public void exe()	{
            new Chowhound().eat();
        }
        private class Chowhound{//吃货
            public void eat(){System.out.println("好吃");}
        }
    }

    在配置文件里加入eat =method.command.EatCommand

    则改动Controller的"open",即c1 =(Command)God.create("eat");就ok。

    ③详细命令类是封装的命令的Command的各种子类,如OpenCommand。在override/改写exe ()时,将命令的运行者与某一操作绑定如tv.open()。尽管简单起见,OpenCommand中通过成员变量如电视/TV设定了运行者,其实,能够通过依赖注入模式,依照配置文件方便地指定消息接收者的类型比如OpenHandler。

    3.吐槽 《设计模式·5.2》

    《设计模式》中,给命令模式(Command Pattern)的定义/意图比較繁琐。正如刀能够砍人,你把刀玩出花样来——来个回马刀都能够,刀的基本作用还是砍人。

    我的定义是:以封装普适方法的命令类层次为桥梁,将通常C/S结构的C与S解耦

    既然命令模式使得C只依赖于Command,它不知道S为何物,也不知道S的接口所以

    C下达的一系列命令,你能够组合成一个队列、能够组合成一个批命令;也能够反之,将C下达的一个命令分解成若干详细的命令;

    对于命令运行前后的变化加以监控,你能够实现undo或redo;假设命令仅仅是改变一个页面的颜色,你非常easyundo/取消操作;假设命令导致手榴弹炸了一个房屋,omg,你undo就非常麻烦。

    你能够玩出其它花样。比方C下达的一个命令open,对于接收者为TV,就打开电视;假设配置的接收者为一个连长,他就打开/攻占一座城门。

    你能够玩出很多其它的花样……


    续 


  • 相关阅读:
    不要在股市上浪费时间(够深刻,耽误自己真本事的提高,即使是价值投资也不值得去做)
    在公司里混日子最终伤害的是你自己
    天使投资人的作用
    115太酷了,居然出了个TV版客户端
    QWidget与HWND的互相转换
    Ubuntu12.10 下搭建基于KVM-QEMU的虚拟机环境(十五)
    QString的不常见用法
    不要神话创业,什么东西都可以自己做,损失就是不拿工资。如果吃不上饭了,那还是不要创业。服务器很便宜
    C++的try catch到底能防止什么错误?
    迷茫的时候,就随机择一去学,时间不要浪费在选择上了
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4288647.html
Copyright © 2011-2022 走看看