命令模式(我的理解)

06-04-12 xyz
命令模式(我的理解)

前言

第一章:通常的命令模式

第二章:简化的命令模式

第三章:其他要说的内容

前言

以下是我对命令模式的理解。可能和很多其他文章讲述的不太一样。经过我理解加工的。供大家参考!学艺不精,并且写的比较仓促,还请大家指教。

通常的命令模式:

1.1通常命令模式有一下几个角色

调用者:(命令的执行者)

生成有序的命令队列

按顺序执行命令操作

提供撤销命令操作

记录已经操作的命令

抽象命令:

抽象的命令接口

具体命令:

具体的命令。

由三个要素组成:执行者,执行者要作的操作和被执行的对象组成。当然还可以有其他,比如将对象执行成什么结果。例如:调用Mypait类(执行者)将My rectangle(对象)填充(操作)为红色(结果)。这样就可以完全描述一个命令了。

执行者:

真正执行逻辑操作的对象

1.2原型:

//调用者

public class Invoker{

List commands; //命令集合

public void setCommands(List commands){

this.commands = commands;

}

public void addCommand (Command command,int i){

commands.add(i,command);

}

public void removeCommand (int i){

commands.add(i,command);

}

//得代执行命令

public void action(){

for(Iterator it = list.iterator();it.hasNext();){

Command command = Command) it.next();

Command. execute();

}

}

……………

//还可以有丰富的redo和undo操作;(当然一些都给基于命令类提供的相应方法)

}

//抽象命令

abstract class Command

{

abstract public void execute();

abstract public void unexecute();

abstract public void reexecute();

//一般有这样这个方法,根据需要可以增删

}

// 具体的命令类1:写作命令,选择一个作者(Author类实例对象),让他写作(调用它的write方法)写作的对象是书(Book的实例对象)形成了一个写作的命令,写作的对象是Book的实例

public class WriteCommand implement Command

{

Author author; //执行者

Book book; //要执行的对象

public WriteCommand (Author author,Book book) {

this. author = author;

this. book = book;

}

// 在这里执行要执行的操作

public override void Execute()

{

author.write (book);

}

}

// 具体的命令类2: 出版命令,选择一个出版社(publisher类实例对象),让他出版书(调用它的publisherBook方法)出版的对象是书(Book的实例对象)形成了一个出版的命令

public class PublishCommand implement Command

{

Publisher publisher;

Book book;

public PublishCommand (Publisher publisher) {

this. publisher = publisher;

this. book = book;

}

// Methods

public override void Execute()

{

publisher. publisherBook(book);

}

}

// Publisher和Author类为执行者

这样我们的客户端代码就可以这样写:

//如果我要出一本书

//一本空白的书

Book book = new Book();

//先找一个作者和出版社

Author author = new Author();

Publisher publisher = new Publisher ();

//产生命令集合

Command writeCommand = new WriteCommand (author,book);

Command publishCommand = new PublishCommand(publisher,book);

List commands = new List ();

Commands.add(writeCommand);

//找个调用者,把命令给它,让他来根据命令协调工作

Invoker invoker = new invoker();

Invoker.setCommands(commands);

public void addCommand (Command command,int i){

commands.add(i,command);

}

invoker.action();

特点:

1》 分布登记统一执行:

在作程序时,经常碰到一些需求,先注册一些操作,并不马上执行,等最终确定后统一执行。如一个具体的例子:用户定制自己的报表,可以订阅饼,柱,折线,曲线图,客户选择相应的报表组合,这样对应一个命令集合,在没确定之前用户可以增删这些报表(命令),等最终确定统一交给调用者根据命令执行,生成组合报表。实现了命令分布提出,确定后统一执行的功能。

2》形如流水线操作:还是出书的例子

//先是一本空白的书:

Book book = new Book();

//找几个作者

Author author1 = new Author();

Author author2 = new Author();

//把写1,2章的名类分别给这两个作者

Command writeCommand = new Write1Command (author1,book);

Command writeCommand = new Write2Command (author2,book);

List commands = new List ();

Commands.add(writeCommand);

//调用者

Invoker invoker = new invoker();

Invoker.setCommands(commands);

//流水写书

invoker.action()

实际上在aciton这一方法中,invoker按照命令,让两个作者流水写作这本书。(类似一个书的流水线加工工厂)

这样我们的书就被流水加工成功(当然这本书只有两章)

这样就给了我们一种系统设计的框架,

模型+工具+命令

客户端产生命令,命令调用工具操作模型。

Book 相当于模型

Author 相当于和多工具类中的一个

Command 命令

3》系统需要支持命令的撤消(undo)。提供redo()方法

我们可以和容易的加入undo和redo,这个不难理解

4》在Invoker中我们可以实现跟踪,和日志。

5》当系统需要为某项复制增加形的功能的时候,命令模式使新的功能(表现为一种命令)很容易地被加入到服务种里。

命令联系了工具类即执行类和系统逻辑,

简化/变化的命令模式:

命令模式的角色比较多,在实际应用种我们可以根据所需要的功能和不需要的功能加以简化。

1》去掉 调用者

产生命令集合后,我们可以直接在client中迭代执行执行操作

2》 变化 调用者 成为 跟踪者

//调用者

public class Invoker{

List commands; //已经执行完毕的命令集合

public void addCommand (Command command,int i){

commands.add(i,command);

}

public void action(Command command){

//执行操作

command. execute();

//

commands.add(command);

}

}

……………

//还可以有丰富的redo和undo操作;(当然一些都给基于命令类提供的相应方法)

}

这样这个类就记录了所有执行过的操作。

3》去掉 命令 用map替代

我们完全可以用map代替命令,这样无需定义各种命令类

我们改进例子

Author author = new Author();

Publisher publisher = new Publisher ();

Map m = new HashMap;

m.put(author, write);

m.put(author, publisherBook);

在Invoker的action方法:

得代map

运用java反射来调用方法;

4》去掉执行者:

直接在命令中(execute方法种)加业务逻辑。这样只适合于简单的小的系统.

其他要说的内容

1》 将某些参数传给某个方发的方式很多,除了当作方法的参数外还可以当作类的成员便俩变量传入:

这就为命令的抽象带来了极大的方便

abstract class Command

{

abstract public void execute();

}

当我们已经有了执行者(类Test)方法execute(args1,args2 ….argsn)

我们不必向Command加入execute(args1,args2 ….argsn)抽象方法,在说即使加了,在我们迭代的时候也无法判断或十分不容易判断哪个命令调用哪个execute方法。

那么我们可以这样

class ConcreteCommand : Command

{

Test test;

args1

args2

…..

argsn

public override void Execute()

{

test. execute (args1,args2 ….argsn);

}

}

2》 在想跟踪操作的时候,一般为每一个操作对象分配一个调用者,操作对象在调用者中设置。(可以抽象出一个总的调用者,来协调调用每一个具体的调用者)

3》 命令的抽象粒度我觉得是要注意的。

4》 理解思想,不要机械的照搬。消化成自己的,加以灵活的运用和创造在是根本出路。

所谓命令模式的根本思想就是在 先形成命令,在根据命令执行。

8
banq
2006-04-13 15:56
不错,实际是一个群命令的使用,单个命令模式粒度太小,让人难以把握,但是多个命令群集合在一起就感觉命令模式的作用。

该文群命令一种用法(流水线操作)实际展示了命令模式+职责链的使用,或者说命令组成的Filter过滤器模式,这种方式可以重构if else逻辑。

使用Map的群命令也是常用的一种过滤器实现,这种方式性能好,也可以重构原来的if else逻辑。

可结合本人的"你还在用if else吗?":

http://www.jdon.com/artichect/ifelse.htm

xyz
2006-04-14 17:05
我觉得命令+组合+责任链比较好用,组合模式的加入,可以使得我们的命令可以随意组合,重用!

zjq545
2006-05-21 20:19
理解的很透彻,不光是讲了概念还 说了具体怎么用。这样才是学以至用

adsedfs
2006-05-21 22:47
顶`````

angelzll
2006-05-21 22:49
写的不错,加深了我对命令模式的理解!

marionette
2006-05-22 08:49
楼主的话真如“大音希声扫阴翳”,犹如”拨开云雾见青天”,使我等网民看到了希望,看到了未来!晴天霹雳,醍醐灌顶或许不足以形容楼主文章的万一;巫山行云,长江流水更难以比拟大师的文才!黄钟大吕,振聋发聩!你烛照天下,明见万里;雨露苍生,泽被万方!透过你深邃的文字,我仿佛看到了你鹰视狼顾,龙行虎步的伟岸英姿;仿佛看到了你手执如椽大笔,写天下文章的智慧神态;仿佛看见了你按剑四顾,江山无数的英武气概!

最后感叹一句:我靠,精辟呀!~

liu3
2006-05-24 22:11
本来想提点意见,结果每看明白.

xyz
2006-05-25 22:24
我已经尽量把命令模式说的很明白了,您仍然不明白的话,我感到遗憾!

power1128
2006-05-27 09:33
小弟初学,不过也看的明白,挺好懂。不过有些地方有错别字和代码错误

比如这个:应该是remove吧

public void removeCommand (int i){

commands.add(i,command);

}

这里也少个参数哈

public PublishCommand (Publisher publisher) {

this. publisher = publisher;

this. book = book;

}

tempaccount
2006-06-02 09:56
受教

seu09
2006-08-25 17:47
小弟是初学者,但是看过之后觉得学到了很多!!!!!

einstein
2007-01-11 17:09
Command writeCommand = new Write1Command (author1,book);

Command writeCommand = new Write2Command (author2,book);

List commands = new List ();

Commands.add(writeCommand);

这里是否有问题?

我感觉应该是这样的吧!

Command write1Command = new WriteCommand (author1,book);

Command write2Command = new WriteCommand (author2,book);

List commands = new List ();

Commands.add(write1Command);

Commands.add(write2Command);

cljspn
2008-03-19 09:09

public PublishCommand (Publisher publisher) {
this. publisher = publisher;
this. book = book;
}
<p>

是不应该这样呢。

public PublishCommand (Publisher publisher,Book book) {
this. publisher = publisher;
this. book = book;
}
<p>

xmuzyu
2008-07-30 20:24
同意命令+组合+责任链的说法,这样确实很好用。一个宏命令确实可以实现责任链。

猜你喜欢
2Go 1 2 下一页