设计模式学习笔记(十七)——Command命令模式

转载 2007年09月18日 18:16:00
设计模式学习笔记(十七)——Command命令模式

Command命令模式介绍:

Command命令模式是一种对象行为型模式,它主要解决的问题是:在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”的问题。如下图:

 

有时我们必须向某对象提交请求,但并不知道关于被请求的操作或请求的接受者的任何信息,此时无法抵御变化的紧耦合是不合适的。如:需要对行为进行“记录、撤销/重做、事务”等处理。我们所要做的是将依赖关系转化,将紧耦合变为松耦合。则上图的形式转化为如下形式:


 

       Command模式通过将请求本身变成一个对象来使行为请求者可向未指定的应用对象提出请求。

       GoF《设计模式》中说道:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

Command命令模式结构:

      

 

 

定义场景:

       现在来看一个场景:对于notepad大家都很熟悉,在我们使用notepad打开一个文档之后,往往做一些操作,如;输入字符(Write)、删除前一个字符(Delete)、撤销刚才的操作(UnDo)。现在我们就用Console程序模拟这个过程。

代码实现与结构分析:

       在实现代码前先说明实现Command模式需要烤炉的一些问题:

1、  一个命令对象应达到何种智能程度:命令对象的能力可大可小。这样就出现了两个极端。一是:它仅确定一个接收者和执行该请求的动作;一是:它自己实现所有功能,根本不需要额外的接收者对象。我给他们起了便于我方便记忆的名字,第一种叫OperationCommand,第二种叫ObjectCommand。当然只是为了便于记忆和理解,如有不理解,在代码实现与结构分析最后我会再谈谈我的想法,如有不妥,还请多提意见,一会在下面的代码中会分别对这两种情况进行示范。

2、  支持取消和重做:为了达到这个目的ConcreteCommand类中要存储额外的状态信息。也就是上图中ConcreteCommandstate属性。

3、  避免取消操作中过程中的错误积累:由于命令重复的执行、取消执行和重执行的过程可能会积累错误,以致一个应用的状态最终偏离初始值。这就有必要在Command中存入更多的信息以保证这些对象可被精确的复原。

下面来看看代码上的实现:首先,我先作一个OperationCommand的例子,先做一个请求的接收者Document(也就是结构图中的Receiver

class Document

    {

        public string strContent;

 

        public Document()

        {

            strContent = "";

        }

}

 

在这个程序中我们还要定义一个抽象类Command,对于OperationCommand类型来说,它仅确定一个接收者和执行该请求的动作。所以,在抽象类Command中,只声明一个Excute的方法。这个方法在其子类中进行实现。(当然这个Command还可以定义成接口)

abstract class Command

    {

        public Command()

        { }

        public abstract void Excute();

}

 

接下来,就要实现各种操作(结构图中的ConcreteCommand),代码如下

//写操作

class WriteCommand : Command

    {

        Document doc;

        ArrayList ObjectState;

        public WriteCommand(Document doc, ArrayList state)

        {

            this.doc = doc;

            ObjectState = state;

        }

 

        public override void Excute()

        {

            doc.strContent += Console.ReadLine();

            ObjectState.Add(doc.strContent);

        }

    }

   

    //删除操作

    class DeleteCommand : Command

    {

        Document doc;

        ArrayList ObjectState;

        public DeleteCommand(Document doc, ArrayList state)

        {

            this.doc = doc;

            ObjectState = state;

        }

 

        public override void Excute()

        {

            doc.strContent = doc.strContent.Substring(0, doc.strContent.Length - 1);

            ObjectState.Add(doc.strContent);

        }

    }

 

    //撤销操作

    class UnDoCommand : Command

    {

        Document doc;

        ArrayList ObjectState;

        public UnDoCommand(Document doc, ArrayList state)

        {

            this.doc = doc;

            ObjectState = state;

        }

 

        public override void Excute()

        {

            doc.strContent = (string)ObjectState[ObjectState.Count - 2];

            ObjectState.Add(doc.strContent);

        }

}

 

实现了各种操作后,编写一个客户代码进行测试

class Program

    {

        static void Main(string[] args)

        {

            Document doc = new Document();

            Console.WriteLine("Please Input next operation:");

            string strOperation = Console.ReadLine();

            Command com = null;

            ArrayList ObjectState = new ArrayList();//Record state

            while (strOperation != "Exit")

            {

                switch (strOperation.ToLower())

                {

                    case "write":

                        com = new WriteCommand(doc, ObjectState);

                        com.Excute();

                        Console.WriteLine("Write Operation:" + doc.strContent);

                        break;

                    case "del":

                        com = new DeleteCommand(doc, ObjectState);

                        com.Excute();

                        Console.WriteLine("Delete Operation:" + doc.strContent);

                        break;

                    case "undo":

                        com = new UnDoCommand(doc, ObjectState);

                        com.Excute();

                        Console.WriteLine("UnDo Operation:" + doc.strContent);

                        break;

                    default:

                        Console.WriteLine("Wrong Operation:");

                        break;

                }

                Console.WriteLine("Please Input next operation:");

                strOperation = Console.ReadLine();

            }

        }

}

 

测试结果:

Please Input next operation:

write

k

Write Operation:k

Please Input next operation:

write

i

Write Operation:ki

Please Input next operation:

write

d

Write Operation:kid

Please Input next operation:

write

d

Write Operation:kidd

Please Input next operation:

del

Delete Operation:kid

Please Input next operation:

undo

UnDo Operation:kidd

Please Input next operation:

 

下面再来实现以下ObjectCommand的例子,首先还是编写一个已存在的请求接收者Document(结构图中的Receiver

class Document

    {

        public string strContent;

 

        public Document()

        {

            strContent = "";

        }

}

 

接下来实现抽象类Command(也可以使用接口),对于ObjectCommand类型来说,它自己实现所有功能,根本不需要额外的接收者对象,所以在Command中声明了所有的操作

abstract class Command

    {

        public Command()

        {  }

 

        public abstract void Write();

        public abstract void Delete();

        public abstract void UnDo();

}

 

有了Command,就可以实现具体的操作类型DocumentCommand(结构图中的ConcreteCommand

class DocumentCommand : Command

    {

        private Document doc;

        private ArrayList ObjectState = new ArrayList();//Record State

        public DocumentCommand(Document doc)

        {

            this.doc = doc;

        }

 

        public override void Write()

        {

            Console.WriteLine("Please input an character:");

            string strRead = Console.ReadLine();

            doc.strContent += strRead;

            ObjectState.Add(doc.strContent);

        }

 

        public override void Delete()

        {

            doc.strContent = doc.strContent.Substring(0, doc.strContent.Length - 1);

            ObjectState.Add(doc.strContent);           

        }

 

        public override void UnDo()

        {

            doc.strContent = (string)ObjectState[ObjectState.Count - 2];

            ObjectState.Add(doc.strContent);

        }

}  

 

接下来就用一个客户端代码作一下测试

class Program

    {

        static void Main(string[] args)

        {

            Document doc = new Document();

            DocumentCommand com = new DocumentCommand(doc);

            Console.WriteLine("Please Input next operation:");

            string strOperation = Console.ReadLine();

            while (strOperation != "Exit")

            {

                switch (strOperation.ToLower())

                {

                    case "write":

                        com.Write();

                        Console.WriteLine("Write Operation:" + doc.strContent);

                        break;

                    case "del":

                        com.Delete();

                        Console.WriteLine("Delete Operation:" + doc.strContent);

                        break;

                    case "undo":

                        com.UnDo();

                        Console.WriteLine("UnDo Operation:" + doc.strContent);

                        break;

                    default:

                        Console.WriteLine("Wrong Operation:");

                        break;

                }

                Console.WriteLine("Please Input next operation:");

                strOperation = Console.ReadLine();

            }

        }

    }

 

测试结果如下:

Please Input next operation:

write

Please input an character:

k

Write Operation:k

Please Input next operation:

write

Please input an character:

i

Write Operation:ki

Please Input next operation:

write

Please input an character:

d

Write Operation:kid

Please Input next operation:

write

Please input an character:

d

Write Operation:kidd

Please Input next operation:

del

Delete Operation:kid

Please Input next operation:

undo

UnDo Operation:kidd

Please Input next operation:

 

这两个程序中需要有几点说明:

1、              对于OperationCommand,我的理解是它所实现的Command只是某一个操作对于某一个接收者,所以我给它取名为OperationCommand。对于ObjectCommand,是实现这样一种对象,它实现了请求接收者的所有操作,所以取名为ObjectCommand

2、              在代码实例中,我对状态的保存处理相对简单,但这是因为利用了String对象的特点,当String对象被修改时,系统会重新分配一块内存。不修改原内存上的内容。如果是要保存其他的引用类型应当注意使用深拷贝,否则,所保存的状态对象都指向一个内存地址,随着状态的改变,保存不了原有的状态。

3、              在对象状态的保存上,我们可以使用Prototype模式。

Command模式的几个要点:

1、  Command模式的根本目的在于将“行为请求者”与“行为实现者”解耦,在面向对象语言中,常见的实现手段是“将行为抽象为对象”。

2、  实现Command接口的具体命令对象ConcreteCommand 有时候根据需要可能会保存一些额外的状态信息。

3、  通过使用Composite模式,可以将多个“命名”封装为一个“复合命令”MacroCommand

4、  Command模式与C#中的Delegate有些类似。但两者定义行为接口的规范有所区别:Command以面向对象中的“接口-实现”类定义行为接口规范,更严格,更符合抽象原则:Delegate以函数签名来定义行为接口规范,更灵活,但抽象能力比较弱

 



      

设计模式学习笔记——命令(Command)模式

设计模式学习笔记——命令(Command)模式@(设计模式)[设计模式, 命令模式, command]设计模式学习笔记命令Command模式 基本介绍 命令案例 类图 实现代码 Command接口 M...

设计模式学习笔记--命令模式command pattern(Java版)

一、实质 将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志以及支持可撤销的操作,也称之为动作ACtion模式、事物transaction模式。 二、结...

【设计模式】学习笔记8:命令模式(Command)

走进命令模式 在餐厅的情境中,我们看看餐厅是怎样工作的: 1、顾客走进餐厅,点好菜后,生成订单交给女服务员。 2、女服务员把订单拿到厨房工作室,大喊一声:“订单来了!” 3、厨师订单准备餐点。 上...

设计模式C++学习笔记之四(Command命令模式)

命令模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。应该是一个比较简单的模式了。 解释  main(),客户  CInvoke...

设计模式C++学习笔记之十二(Command命令模式)

设计模式C++学习笔记之十二(Command命令模式) 命令模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。应该是一个比较...

设计模式C++学习笔记之十二(Command命令模式)

设计模式C++学习笔记之十二(Command命令模式) 命令模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。应该是一个比较...

设计模式C++学习笔记之十二(Command命令模式)

博文很精彩,为方便个人学习特转载,地址:http://www.cnblogs.com/wanggary/archive/2011/04/18/2020230.html 命令模式,将一个请求封装为...
  • phiall
  • phiall
  • 2016年03月17日 22:50
  • 207

【设计模式学习笔记十五】【行为模式】【命令模式(Command)】

命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。别名又称动作模式或事务模式。 我应该理解和掌握的: 1)能够画出这个设计模式...

java 设计模式学习笔记十二 command命令设计模式

command命令设计模式 类似于callback的功能,就是将所有事件的处理方法归并到一起,客户端不需要知道 具体处理代码。这样在以command中代码发生变化时,客户端不需要作修改 ...

设计模式C++学习笔记之十七(Chain of Responsibility责任链模式)

17.1.解释 概念:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 main(),客户 IWo...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:设计模式学习笔记(十七)——Command命令模式
举报原因:
原因补充:

(最多只允许输入30个字)