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

Command命令模式介绍:

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

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

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

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

Command命令模式结构:

      


 

定义场景:

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

代码实现与结构分析:

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

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

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

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 = newWriteCommand(doc, ObjectState);

com.Excute();

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

break;

case "del":

com = newDeleteCommand(doc, ObjectState);

com.Excute();

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

break;

case "undo":

com = newUnDoCommand(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以函数签名来定义行为接口规范,更灵活,但抽象能力比较弱

http://www.cnblogs.com/kid-li/category/44668.html

转载于:https://www.cnblogs.com/xiayong123/p/3716998.html

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

  1. 【HeadFirst 设计模式学习笔记】6 命令模式

    1.这一节我们的任务是创建一个类似智能家居的万能遥控器,控制各种家电.我们需要将"请求"封装成对象(一个命令对象通过在特定接收者上绑定一组动作来封装请求),以便使用不同的请求.队列 ...

  2. 设计模式自学笔记007_Real(命令模式、备忘录模式、桥接模式)

    设计模式自学笔记007_Real(命令模式.备忘录模式.桥接模式) 一.命令模式 在软件设计的过程中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道请求的操作是哪个.我们只需要 ...

  3. 设计模式学习笔记——享元(Flyweight)模式

    设计模式学习笔记--享元(Flyweight)模式 @(设计模式)[设计模式, 享元模式, flyweight] 设计模式学习笔记享元Flyweight模式 基本介绍 享元案例 类图 实现代码 Big ...

  4. 设计模式学习笔记——中介者(Mediator)模式

    设计模式学习笔记--中介者(Mediator)模式 @(设计模式)[设计模式, 中介者模式, Mediator] 设计模式学习笔记中介者Mediator模式 基本介绍 中介者案例 类图 实现代码 Me ...

  5. 设计模式学习笔记——单例(Singleton)模式

    设计模式学习笔记--单例(Singleton)模式 @(设计模式)[设计模式, 单例模式, Singleton, 懒汉式, 饿汉式] 设计模式学习笔记单例Singleton模式 基本介绍 单例案例 类 ...

  6. 设计模式学习笔记--Mediator 中介者模式

    我们知道面向对象应用程序是由一组为了提供某种服务而彼此交互的对象组成.当彼此引用的对象数量比较少时,此时对象之间就为直接交互(点对点).而当对象的数量增加时,这种直接交互会导致对象之间复杂的.混乱的引 ...

  7. 设计模式学习笔记--Flyweight享元模式

    Flyweight模式也叫享元模式,是由GoF提出的23种设计模式中的一种.Flyweight模式是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用,所以叫享元.   此模式解决的是由于大量 ...

  8. 设计模式学习笔记--享元(Flyweight)模式

    写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式:每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案:当我们碰到模式 ...

  9. 【设计模式】学习笔记8:命令模式

    本文出自   http://blog.csdn.net/shuangde800 走进命令模式 在餐厅的情境中,我们看看餐厅是怎样工作的: 1.顾客走进餐厅,点好菜后,生成订单交给女服务员. 2.女服务 ...

  10. C#设计模式学习笔记:(4)建造者模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7614630.html,记录一下学习过程以备后续查用.一.引言在现实生活中,我们经常会遇到一些构成比较复杂的物 ...

最新文章

  1. 快速在PowerPoint文档中添加图表
  2. The Excel Connection Manager is not supported in the 64-bit version of SSIS, as no OLE DB provider i
  3. Ajax获取数据的流程
  4. P2038 无线网络发射器选址
  5. (7)JavaScript字面量
  6. import和class关键字的区别
  7. 视频|光学3D测量技术原理及应用
  8. Python 3 实现选择排序
  9. c语言数组指针移位,C语言数组指针_3
  10. [笔记]MacOs BootCamp装Win10双系统 经历
  11. mysql应用教程李辉答案_数据库系统原理及mysql应用教程李辉答案章节期末答案...
  12. 自由-进化/开源中国众包平台
  13. [6.15] 心态 信念
  14. 解决跨域(六)--- document.domian
  15. JAVA学习:基础入门(下)
  16. 基于android的手机掌上购物
  17. win10的远程桌面控制
  18. FreeBSD中安装源的方法
  19. Ethercat学习日记
  20. Tomcat7w.exe无法start

热门文章

  1. linux扩大 boot分区大小,Ubuntu扩大boot空间
  2. python时间计算_python datetime库使用和时间加减计算
  3. 使用临时表解决union和order by不能同时使用的问题
  4. hp-ux锁定用户密码_我们如何简化925移动应用程序的用户入门— UX案例研究
  5. 海浪 shader_海浪下的发现
  6. 深入 Adobe Reader 保护模式 —— 第一部分 —— 设计
  7. 解决npm 的 shasum check failed for错误
  8. 解决git提交问题error: The requested URL returned error: 403 Forbidden while accessing
  9. AI x 量化:华尔街老司机解密智能投资正确姿势
  10. typescript+react+antd基础环境搭建