行为型模式(五):命令模式

命令模式属于23种设计模式中行为模式中的一个,它也是一种简单实用非常普遍的设计模式。
首先看下GOF对命令模式的定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式主要应用于将行为调用者与实现者解耦。比如我们以前惯用的写代码的方式是LogicProcess logic = new LogicProcess(); 然后紧接着调用实现方法logic.process(),这种写法其实非常普遍,但这种写法把行为调用者和行为实现者耦合在了一起,一般情况下并没有什么问题的,但当调用逻辑比较复杂或则调用行为有多种实现时就非常不利于程序的扩展。
命令模式的适用场景描述:
(1)整个调用过程比较繁杂,或者存在多处这种调用。使用Command类对该调用加以封装,便于功能的再利用。
(2)调用前后需要对调用参数进行某些处理。
(3)调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。
命令模式结构图如下:

img

wKioL1MXQNnzDmOuAAE_6jCA_qk028.jpg

命令模式的参与角色:
(1)抽象命令角色(Command):抽象命令,包含命令执行的抽象方法
(2)命令接收者(Receiver):命令接收者角色,它包含所有命令的具体行为实现方法。
(3)具体命令角色(ConcreteCommand):它包含一个命令接收者对象,并调用接收者的对象相应实现方法。
(4)命令调用者角色(Invoker):提供给客户端调用,接收客户端所传递的具体命令对象。
下面看具体代码实现:
1、第一个文件抽象命令角色:Command.java

/**
* 抽象命令接口
*/
public interface Command {
/**
* 命令执行方法
*/
public void execute();
}

2、第二个文件命令接收者角色:Document.java

/**
* 命令接收者 Receiver
*/
public class Document {
/**
* 操作实体对象
*/
public static StringBuffer sbr = new StringBuffer();
/**
* 计数器
*/
public static int count = 0;
/**
* 撤销实现方法
*/
public void undo(){
System.out.println("调用撤销实现方法,字符串递减");
sbr.deleteCharAt(sbr.length()-1);
count --;
System.out.println("当前文本为:" + sbr.toString());
}
/**
* 恢复实现方法
*/
public void redo(){
System.out.println("调用恢复实现方法,字符串递加");
this.sbr.append(count);
count ++;
System.out.println("当前文本为:" + sbr.toString());
}
/**
* 执行实现方法
*/
public void add(){
System.out.println("调用执行实现方法,字符串递加");
this.sbr.append(count);
count ++;
System.out.println("当前文本为:" + sbr.toString());
}
}

3、第三个文件具体命令角色:AddCommand.java

/**
* 执行命令实现类
*/
public class AddCommand implements Command {
/**
* 命令接受者对象
*/
public Document doucment;
/**
* 构造方法
* @param document
*/
public AddCommand(Document document){
this.doucment = document;
}
@Override
public void execute() {
// TODO Auto-generated method stub
this.doucment.add();
}

4、第四个文件具体命令角色:UndoCommand.java

/**
* 撤销命令实现类
*/
public class UndoCommand implements Command {
/**
* 命令接受者对象
*/
public Document doucment;
/**
* 构造方法
* @param document
*/
public UndoCommand(Document document){
this.doucment = document;
}
@Override
public void execute() {
// TODO Auto-generated method stub
this.doucment.undo();
}
}

5、第五个文件具体命令角色:RedoCommand.java

/**
* 恢复命令实现类
*/
public class RedoCommand implements Command {
/**
* 命令接受者对象
*/
public Document doucment;
/**
* 构造方法
* @param document
*/
public RedoCommand(Document document){
this.doucment = document;
}
@Override
public void execute() {
// TODO Auto-generated method stub
this.doucment.redo();
}
}

6、第六个文件调用者角色:Invoker.java

/**
* 提供给客户端的命令调用方法
* @author feng
*
*/
public class Invoker {
/**
* 命令对象
*/
public Command command;
/**
* 命令设置方法
* @param command
*/
public void setCommand(Command cmd){
this.command = cmd;
}
/**
* 命令执行方法
*/
public void execute(){
this.command.execute();
}
}

7、第七个文件TestMain.java

/**
* 测试Main方法
*/
public class TestMain {
public static void main(String args[]){
Document doc = new Document(); //文档实体对象
AddCommand addCmd = new AddCommand(doc); //具体命令实体对象
UndoCommand undoCmd = new UndoCommand(doc); //具体命令实体对象
RedoCommand redoCmd = new RedoCommand(doc); //具体命令实体对象
Invoker invoker = new Invoker(); //调用者对象
invoker.setCommand(addCmd);
invoker.execute();
invoker.setCommand(addCmd);
invoker.execute();
invoker.setCommand(undoCmd);
invoker.execute();
invoker.setCommand(redoCmd);
invoker.execute();
}

虽然代码看似挺多,但其实命令模式的结构还是比较清晰的,总的来说命令模式的使用流程就是首先创建一个抽象命令,然后创建多个具体命令实现抽象命令接口,然后创建一个命令接受者角色,它包含各种的行为的具体实现,然后再有一个命令调用者角色,提供给客户端,用于接收客户端的参数。
下面总结下命令模式的优点:
(1)命令模式将行为调用者和各种行为分隔开,降低程序的耦合,便于程序扩展。
(2)命令模式将行为的具体实现封装起来,客户端无需关心行为的具体实现。
(3)命令模式可为多种行为提供统一的调用入口,便于程序对行为的管理和控制。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,928评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,748评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,282评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,065评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,101评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,855评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,521评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,414评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,931评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,053评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,191评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,873评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,529评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,074评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,188评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,491评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,173评论 2 357

推荐阅读更多精彩内容