六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 169|回复: 0

设计模式学习之Command模式

[复制链接]

升级  18%

23

主题

23

主题

23

主题

秀才

Rank: 2

积分
77
 楼主| 发表于 2012-12-29 11:14:09 | 显示全部楼层 |阅读模式
<div id="cnblogs_post_body">今天学习了命令模式,这个模式非常的给力,它能将命令封装起来让另外的执行者去执行,相当于一个命令的收集和转发过程,而且,这个模式还能将一系列的命令组合成“命令宏”,并且可以轻松的完成撤销的操作,非常适合日志系统或事务处理系统,也常用于窗口编程中的菜单命令处理,好了,下面回顾一下这个模式吧

  • 命令模式:
    将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
  • 适用性:

    • 抽象出待执行的动作以参数化某对象,你可用过程语言中的回调(callback)函数表达这种参数化机制。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。Command 模式是回调机制的一个面向对象的替代品。
    • 在不同的时刻指定、排列和执行请求。一个Command 对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。
    • 支持取消操作。Command 的Excute 操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command 接口必须添加一个Unexecute 操作,该操作取消上一次Execute 调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute 和Execute 来实现重数不限的“取消”和“重做”。
    • 支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。在Command 接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute 操作重新执行它们。
    • 用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务( transaction )的信息系统中很常见。一个事务封装了对数据的一组变动。Command 模式提供了对事务进行建模的方法。Command 有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。     
       
这个模式怎么举例呢?既然是命令模式,那么就找一些需要发送命令的场合吧,最常见的当然是软件中的菜单了,每一个菜单对应一个命令,当用户点击菜单的时候就会调用与菜单相关联的命令了,那么怎么来使用命令模式构建菜单呢,看代码:
<div class="cnblogs_code" style="background-color: #f5f5f5; border: #cccccc 1px solid; padding: 5px;">//菜单接口public interface IMenu{    public Item getItem(int itemIndex);    public void addItem(Item item);    public int getItemLength();    public void setItem(int itemIndex, Command command);    public void isClicked(int itemIndex);}public class Menu implements IMenu{    protected Item[] items;    protected int itemLength;    private String title;    public Menu(String title)    {        this.title=title;    }    public Item getItem(int itemIndex) throws OverflowException    {        if(itemIndex<0 || itemIndex>itemLength-1)        {            throw new OverflowException("out of range");        }        return items[itemIndex];    }    public void addItem(Item item)    {        if(item != NullItem)        {            items.add(item);        }    }    public void setItem(int itemIndex, ICommand command)    {        if(itemIndex<0 || itemIndex>itemLength-1)        {            throw new OverflowException("out of range");        }        Items[itemIndex].setCommand(command);    }    public void  isClicked(int itemIndex)    {        this.getItem(itemIndex).isClicked();    }}//菜单项目public class Item{    private Command command;    private String title;    public Item(String title)    {        this.title=title;    }    public void setCommand(ICommand command)    {        this.command=command;    }    public void  isClicked()    {        this.command.execute();    }}//命令接口public interface ICommand{    public void execute();}//保存命令public class SaveCommand implements ICommand{    Document document;    public SaveCommand(Document document)//document参数为接受者    {        this.document=document;    }    public void execute()    {        if(document.isModified())        {            document.save();        }    }}//打开命令public class OpenCommand implements ICommand{    Application application;    public OpenCommand(Application application)    {        this.application=application;    }    public void execute()    {        Document document=application.open();        application.addToWorkplace(document);    }}//退出命令public class ExitCommand implements ICommand{    Application application;    public ExitCommand(Application application)    {        this.application=application;    }    public void execute()    {        Document document;        for(document=Application.currentDocument(); document!=NullDocument; document=Application.nextDocument())        {            if(document.isModified())            {                document.alertSave("您还有修改过的文档尚未保存,是否保存?");            }        }        application.exit();    }}//剪切命令public class CutCommand implements ICommand{    SelectedBlock selectedBlock;    public CutCommand(SelectedBlock selectedBlock)    {        this.selectedBlock=selectedBlock;    }    public void execute()    {        System.Clipboard.save(selectedBlock);        selectedBlock.delete();    }}//粘贴命令public class PasteCommand implements ICommand{    Document document;    Object pasteObject    public PasteCommand(Document document, Object pasteObject)    {        this.document=document;        this.pasteObject=pasteObject;    }    public void execute()    {        document.insertAt(document.currentCursor(), pasteObject);    }}public class SaveAllCommand implements ICommand{    Application application;    public SaveAllCommand(Application application)    {        this.application=application;    }    public void execute()    {        Document document;        for(document=application.currentDocument(); document!=NullDocument; document=application.nextDocument())        {            if(document.isModified())            {                document.save();            }                    }    }}//客户代码public class Client{    public static void main(String[] argv)    {        /*        *    创建编辑器和新建文档        */        Application application=new Application("文件编辑器");        Document document=application.new("命令模式日志");        application.addToWorkplace(document);        /*        *    创建菜单,项目,命令对象        */        Menu menuFile=new Menu("文件菜单");        Menu menuEdit=new Menu("编辑菜单");        Item itemSave=new Item("保存");        Item itemOpen=new Item("打开");        Item itemExit=new Item("退出");        menuFile.addItem(itemSave);        menuFile.addItem(itemOpen);        menuFile.addItem(itemExit);        Item itemCut=new Item("剪切");        Item itemPaste=new Item("粘贴");        menuEdit.addItem(itemCut);        menuEdit.addItem(itemPaste);        ICommand commandSave=SaveCommand(document);        ICommand commandOpen=OpenCommand(application);        ICommand commandExit=ExitCommand(application);        ICommand commandCut=CutCommand(document.selectedBlock());        ICommand commandPaste=PasteCommand(document, System.clipboard.currentObject);        /*        *    赋予每个项目相应的命令        */        menuFile.setCommand(0, commandSave);        menuFile.setCommand(1, commandOpen);        menuFile.setCommand(2, commandExit);        menuEdit.setCommand(0, commandCut);        menuEdit.setCommand(1, commandPaste);        /*        *    模拟菜单操作        */        menuFile.isClicked(0);//点击保存        menuFile.isClicked(1);//点击打开        //用鼠标选中一行文字        menuEdit.isClicked(0);//点击剪切        //将光标移动到任意位置        menuEdit.isClicked(1);//点击粘贴        menuFile.isClicked(2);//点击退出    }}
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表