文档章节

学习设计模式——命令模式

江左煤郎
 江左煤郎
发布于 2018/10/22 00:08
字数 1572
阅读 17
收藏 0

任何模式的出现,都是为了解决一些特定的场景的耦合问题,以达到对修改封闭,对扩展开放的效果。命令模式也不例外:

命令模式是为了解决命令的请求者和命令的实现者之间的耦合关系。

解决了这种耦合的好处我认为主要有两点:

1.更方便的对命令进行扩展(注意:这不是主要的优势,后面会提到)

2.对多个命令的统一控制(这种控制包括但不限于:队列、撤销/恢复、记录日志等等)

模式解析:

经典的命令模式包括4个角色:

Command:定义命令的统一接口

CommondImpl:Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。

Receiver:命令的实际执行者

Invoker:命令的请求者,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。

下面对上面四个角色的经典实现用代码来进行说明,这也是大部分文章对命令模式的运用方式。

经典代码实现:

/*
 * 命令接口,声明执行的操作
 */
public interface Commond {
	/*
	 * 执行命令对应的操作
	 */
	public void excute();
}
/**
 * @ClassName:CommondImpl
 * @Description:命令接口的具体实现类
 */
public class CommondImpl implements Commond{
	/*
	 * 持有相应的接收者对象
	 */
	Receiver receiver;
	//示意属性,命令对象可以有自己的属性
	public int state;
	//构造方法,传入接收者对象
	public CommondImpl(Receiver r){
		receiver=r;
	}
	//调用接收者的对于功能方法,由接收者执行具体的功能
	@Override
	public void excute() {
		//可以做一些其他处理
		receiver.action();
	}
}
/**
 * @ClassName:Receiver
 * @Description:接收者类
 */
public class Receiver {
	/**
	 * @Title:action
	 * @Description:示意操作,真正执行命令相应的操作
	 */
	public void action(){
		//功能代码
	}
}
/**
 * @ClassName:Invoker
 * @Description:在应用程序中通过该类来触发执行命令
 */
public class Invoker {
	private Commond commond;

	public void setCommond(Commond commond) {
		this.commond = commond;
	}
	//调用命令对象执行方法
	public void runCommond(){
		commond.excute();
	}
}
//客户端调用
public class Client {
	public static void main(String[] args) {
		//组装命令对象与接收者对象,将命令对象与接收者对象建立起联系
		Receiver r=new Receiver();
		Commond c=new CommondImpl(r);
		//创建Invoker对象,并设置命令对象,然后运行命令
		Invoker invoker=new Invoker();
		invoker.setCommond(c);
		invoker.runCommond();
	}
}

经典实现解析:

 不知道大家看过上面的代码之后是什么感觉,反正我看过上面的代码之后第一反应确实是越看越糊涂了,主要觉得有几点疑问:

1. 执行命令可以,但是为什么要用命令封装起来,这不是有点脱裤子放屁的感觉么?我完全可以这样写:

public class Client {
	public Client() {
		Receiver receiver = new Receiver();
		receiver.action();
	}
}

这样不是更加简单明了?两个类搞定。

2. 通过继承Command之后,增加命令怎么增加?比如增加一个命令,要改动3个地方:增加一个Command实现,修改Receiver类,修改Client。这好像没有对修改关闭啊?

3. CommondImpl与Receiver类完全耦合了啊,要是有CommondImpl以及另一个不同的CommondImpl要执行的命令在不同的Receiver中怎么办?

那来看看到底疑问在哪里:

1. 确实可以两个类来搞定。但我们要牢记命令模式的初衷:对命令请求者(Invoker)和命令实现者(Receiver)的解耦,方便对命令进行各种控制。打个比方,现在我们要对CommondImpl以及其他一系列命令进行日志记录,并且两个命令之间的操作间隔不能大于1秒。这种情况下要直接用两个类就会有大量的业务逻辑要在客户端进行处理,当命令增加,对每个命令的控制增加时,就会在Client里面产生大量的变化点,这样耦合就出来了,但是采用命令模式之后,对着一系列的命令我们都可以进行控制,这就是对变化点的封装,

2. 增加命令:采用命令模式的时候,我感觉最大的耦合点变化到了Receiver和CommondImpl之间,当然我们可以对Receiver进行抽象,采用接口或者抽象类来封装这个变化,但实际情况中我们会遇到多个命令来至于不同的Receiver,比如A命令来至于ReceiverA,B命令来至于ReceiverB,这种情况下我们怎么应对命令的新增?对这种情况我的理解是命令模式并不能也不需要解决这个问题,因为命令模式的操作单元已经细化到了每一个具体的功能上面,当增加一个具体功能的时候是没有很好的办法对功能实现类进行修改关闭的(当然你可以把每个功能方法放到一个类中,但确实没必要,这个粒度已经很小了),实际上也没有必要的。

适用场景:

1. 命令的发送者和命令执行者有不同的生命周期。命令发送了并不是立即执行。

2. 命令需要进行各种管理逻辑。

3. 需要支持撤消\重做操作(这种状况的代码大家可以上网搜索下,有很多,这里不进行详细解读)。

结论:

 通过对上面的分析我们可以知道如下几点:

1. 命令模式是通过命令发送者和命令执行者的解耦来完成对命令的具体控制的。

2. 命令模式是对功能方法的抽象,并不是对对象的抽象。

3. 命令模式是将功能提升到对象来操作,以便对多个功能进行一系列的处理以及封装。

本文转载自:https://www.cnblogs.com/konck/p/4199907.html

共有 人打赏支持
江左煤郎
粉丝 26
博文 86
码字总数 220642
作品 0
西安
后端工程师
私信 提问
设计模式已经陨落了?

你现在是坐在一个程序员旁边吗?如果是的话,那么在你读下面的段落之前,有一个简单的实验。让他们到一边去,问问他们两个问题并记录下答案。首先问他们“什么是设计模式?”然后再问“说出你...

oschina
2014/03/11
9.1K
69
《JavaScript设计模式与开发实践》原则篇(2)—— 最少知识原则

最少知识原则(LKP)说的是一个软件实体应当尽可能少地与其他实体发生相互作用。这 里的软件实体是一个广义的概念,不仅包括对象,还包括系统、类、模块、函数、变量等。 单一职责原则指导我们...

嗨呀豆豆呢
2018/12/30
0
0
《JavaScript设计模式与开发实践》最全知识点汇总大全

系列文章: 《JavaScript设计模式与开发实践》基础篇(1)—— this、call 和 apply 《JavaScript设计模式与开发实践》基础篇(2)—— 闭包和高阶函数 《JavaScript设计模式与开发实践》模式...

嗨呀豆豆呢
01/04
0
0
编程中的那些套路——关于策略模式

该文章属于《编程中的那些经典套路——设计模式汇总》系列,并且以下内容基于语言PHP 今天讲讲策略模式,策略模式 和工厂模式十分相像(或者说在代码逻辑层面,他们是一样的)。 但策略模式与...

gzchen
2018/08/27
0
0
编程中的那些经典套路——设计模式汇总

在正式阅读前,我先谈谈我们该用什么姿势和心态学习设计模式: 如果你还没有过多的编程经验(泛指半年以下),我建议你把它当做小说来看,能看懂多少是多少,因为半年以下经验的程序员用到设...

gzchen
2018/08/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

c++ 定义新的异常

#include <iostream> #include <exception> using namespace std; struct MyException : public exception { const char * what () const throw () { return "C++ Exception"; } }; int main......

天王盖地虎626
今天
3
0
PDMan-2.1.1 发布:用心开源,免费的国产数据库建模工具(春节前最后一个版本)

一、软件介绍 PDMan 是一款开源免费的数据库模型建模工具,是PowerDesigner之外另一种更好的选择。支持Windows,Mac,Linux等操作系统,具有上手容易,使用简单的特点。 2018年获得码云GVP (Gi...

O龙猫O
今天
17
0
OSChina 周二乱弹 —— 以后我偷小鱼干养你

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @庞巴哥 :只有这节奏瞬间变得轻松。。。。。。。。。分享Talking Eyes的单曲《In the sun (Extended Version)》: 《In the sun (Extended Ve...

小小编辑
今天
374
7
多表查询

第1章 多表关系实战 1.1 实战1:省和市  方案1:多张表,一对多  方案2:一张表,自关联一对多 1.2 实战2:用户和角色 (比如演员和扮演人物)  多对多关系 1.3 实战3:角色和权限 (比如...

stars永恒
今天
9
0
求推广,德邦快递坑人!!!!

完全没想好怎么来吐槽自己这次苦逼的德邦物流过程了,只好来记一个流水账。 从寄快递开始: 2019年1月15日从 德邦物流 微信小app上下单,截图如下: 可笑的是什么,我预约的是17号上门收件,...

o0无忧亦无怖
昨天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部