Pattern-Oriented Software Architecture v1巨详细读书笔记 3

本笔记[不]是从《面向模式的软件体系架构 卷1 模式系统》摘抄,而是《Pattern-Oriented Software Architecture vol.1 A system of patterns》原书[page 282-286]的翻译组成,主要内容为如何实现command processor模式!

---------------------------------------------------


[282]
[实现]
执行以下步骤可以实现此模式:
    1 定义abstract command接口。abstract command类隐藏特定command的细节,定义执行command的抽象方法,同时定义了支持command processor提供的附加服务的必要方法,例如,名为‘getNameAndParameters’的方法为记录command的日志提供支持。
    我们将TEDDI中的‘撤销’机制分为三种command类型,将他们定义成枚举类型,因为command类型有可能像第3步一样动态改变:
    No change:不需要‘撤销’的command,光标移动就属于此类。
    Normal:可被‘撤销’的command,在文本中替换单词就属于此类。
    No undo:不能被‘撤销’的command,防止撤销之前执行的normal command。
    如果要把我们的文本变成‘政治上正确‘的文本,把‘他’替换成‘他/她’,TEDDI将需要存储文档中所有相应的位置,以备撤销,对于在全文档这样的替换操作将导致潜在的大量存储,这也就促使我们将这种command归类为‘no undo’。
    class AbstractCommand {
    public:
        enum CmdType { no_change, normal, no_undo } ;
        virtual -Abstractcommand ( ) ;
        virtual void doit () ;
        virtual void undo ( ) ;
        CmdType getType() const { return type;)
        virtual String getName() const { return "NONAME";}
            // gives name of command for selection
            // in undo/redo menu
    protected:
        CmdType type;
        Abstractcommand (CmdType t=no_change) : type (t ) { }
    };
    方法getName()可以用来在用户选择‘撤销’命令时显示最近执行过的command名称。

    2 为应用程序支持的每种请求类型设计command组件。绑定supplier和command的方式有多种:将supplier硬编码到command中,或controller将supplier以command构造函数的参数形式传给它。对于第二种选项,多文档编辑器就是一个很好的例子,在多文档编辑器中,command会连接到一个特定的文档对象。
    TEDDI中的‘删除‘command将表示文本的对象作为他第一个参数,需要删除的字符范围作为后面两个参数:
    class DeleteCmd : public AbstractCommand {
    public:
        DeleteCmd(TEDD1_Text *t, int start, int end)
            : ~bstractcornman(dn ormal) , mytext (t) ,
            from (start) , to (end) {/*...*/}

        virtual -DeleteCmd();
        virtual void doit();
            // delete characters in mytext
            // between from and to and save them in delstr
        virtual void undo ( ) ;
            // insert delstr again at position from
        String getName() const { return "DELETE" + delstr;}
    protected:
        TEDDI_Text *mytext;// plan for multiple text buffers
        int from,to; // range of characters to delete
        String delstr; // save deleted text for undo
    };
    在doit()的实现中,将调用TEDDI_Text中提供的deleteText()。
    Command对象也许会要求用户提供更多的参数。TEDDI提供‘load text file’命令,例如,弹出一个输入装载文件名的对话框,在此情况下,事件处理系统应该将用户输入转给command,而不是controller。(Commands that require user interaction during their creation or execution therefore call for additional care.)需要与用户交互的command,在被创建或执行时需要特殊处理。事件处理系统(已经超出此模式的讨论范围)必须能处理这种情况。
    可撤销的command可以使用Memento模式[GHJV95]在不破坏封装性的前提下存储supplier的状态以备撤销。

[284]
    3 通过组合多个连续的command组成一个macro command,增加灵活性。可以应用Composite模式[GHJV95]来实现这种macro command组件。
    在TEDDI中,实现macro command类,允许用户定义经常使用的的命令序列快捷方式:
    class MacroCmd : public AbstractCommand {
    public :
        MacroCmd(String name, AbstractCommand *first)
            : AbstractCommand ( first ->getType 0 ) ,
            macroname(name) { / * . . . * / }
        virtual -MacroCmd();
        virtual void doit ( ) ;
            // do every command in cmdlist
        virtual void undo () ;
            // undo all commands in cmdlist in reverse order
        virtual void finish(); // delete commands in cmdlist
        void add(Ab-stractcommand *next) {
            cmdlist.append(next) ;
            if (next - >getType ( ) == no-undo) type = no-undo;
            /* ... * / }
        String getName ( ) const { return macroname; }
    protected:
        String macroname;
        OrderedCollection<AbstractCommand*> cmdlist;
    } ;
    MacroCmd的command类型依赖于添加到macro中的command,添加了no-undo类型的command将避免在整个macro command上做撤销操作,否则undo()将从反方向在cmdlist的每个普通command对象上做撤销操作,当然在此过程中会跳过类型为no-change的command。

    4 实现controller组件。controller可以采用创建型模式(如:Abstract Factory和Prototype模式[GHJV95])创建command对象,当然,controller已经从supplier组件中解偶了,这种另外的解偶模式不是必须的。应用程序中的controller提供的菜单是Prototype模式应用的一个很好的例子,controller中包含了每个菜单项的command原型
,当用户选择菜单项时,controller将相应command原型的一个拷贝传递给command processor处理,如果这样的一个支持菜单的controller能被动态地用macro command对象配置,那就能很容易地实现用户自定义菜单。
[285]
    TEDDI的用户交互是通过controller中的回调过程处理,在回调过程中将创建相应的command对象,并把它传递给command processor,TEDDI采用了theCP这个全局变量来引用唯一的一个command processor组件。
    void TEDDI_control1er::deleteButtonPressed() {
        AbstractCommand *delcmd =
            new DeleteWordConunand(
                this->getcursor(),// pass cursor position
                this->getText()); //pass text
        theCP ->perform (delcmd) ;
    }
    在程序一启动的时候,回调函数deleteButtonPressed()就被注册到了事件处理系统中。

    5 实现command processor提供的附加服务访问点。用户可访问的附加服务通常用特定的command类实现;command processor提供完成服务功能的方法,也可以通过直接调用command processor中的方法来访问附加服务;但比如command日志一类的内部服务应该自动被command processor执行。
    类UndoCommand可以访问TEDDI的撤销机制,此类同command processor的内部数据协作,因此被定义成command processor的友元(译者注:c++中的friend)。注意:类UndoCommand需分类为no-change,不能被command processor存储下来。
    class UndoCommand : public AbstractCommand {
    public:
        UndoCommand ( )
            : AbstractCommand(no_change) { }
        virtual ~Undocommand ( ) ;
        virtual void doit() { theCP->undo_lastcmd(); }
    } ;

    UndoCommand中的doit()请求command processor撤销最后执行的一次普通操作。类RedoCommand则提供了相反的功能,它的方法doit()将使command processor重新执行一次已经撤销的命令。

[286]
    6 实现command processor组件。command processor接收从controller传递过来的command对象并管理他们,调用每个command对象的‘do’方法执行其命令。例如:用c++实现的command processor将负责删除不再使用的command对象。
    可以应用singleton模式[GHJV95]确保只有一个command processor存在。
    在TEDDI中,我们采用2个栈实现多层撤销/重做的功能,一个栈保存执行过的命令,另一个保存已经撤销的命令:
    class Commandprocessor {
    pub1ic :
        CommandProcessor ( ) ;
        virtual ~CommandProcessor();
        virtual void do_cmd(AbstractCommand *cmd) {
                // do cmd and push it on donestack
            cmd->doit () ;
            switch(cmd->getType()) {
            case AbstractCommand::normal:
                donestack .push (cmd) ; break;
            case AbstractCommand::no_undo:
                dones tack. make_empty ( ) ;
                undonestack .make_empty () ;
                    // Fall through:
            case AbstractCommand::no-change:
                    // take responsibility for command objects:
                delete cmd;
            break;
            }
        }
        friend class UndoCommand; // special relationship
        friend class Redocommand; // special relationship
    private:
        // this method is only used by Undocommand
        virtual void undo_lastcmd() ;
                // pop cmd from donestack,
                // undo it, and push it on undonestack
            // this method is only used by Redocommand
        virtual void redo_lastundone() {
            AbstractCommand *last = undonestack.pop();
            if (last) this->do-cmd(1ast);
        }
    private:
        Stack<AbstractCommand*> donestack,undonestack;
    } ;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值