请不要用命令的口吻关系你在乎的人 — dufy
在巴厘岛开的奶茶店开张后,生意很红火,每天都要忙到很晚,晚上就要打开奶茶店的酷炫的灯,由于安装了不同的灯,灯的开关都不在一个地方,那么需要打开和关闭所有的灯就很麻烦。作为老板的我,每天都要去开灯和关灯,这种粗活可不能交给设计模式MM去做啊。(pS:每个灯一个开关,并且不在一个地方,每次只能打开一个或者关闭一个灯)。
我将上面描述的事情用代码表示:
public class Boss {
private String name;
private KuXuanLight kuXuanLight = new KuXuanLight();
public Boss(String name){
super();
this.name = name;
}
public void openLight(){
System.out.println("----晚上了,天黑了,准备开灯---");
kuXuanLight.open();
System.out.println("----开灯完成---");
}
public void closeLight(){
System.out.println("----下班了,准备关灯---");
kuXuanLight.close();
System.out.println("----关灯完成---");
}
}
public class Test {
public static void main(String[] args) {
Boss boss = new Boss("奶茶店老板");
//天黑开灯,一定要开,因为不是黑店
boss.openLight();
//下班关灯,一定要关,因为不能浪费电,做新时代的好青年
boss.closeLight();
}
}
上面就是我作为老板每天一定要做的事情。设计模式MM看到后,很是心疼我啊,说我一天这么累,还要亲自去开灯和关灯(我的职责太多了),并且我还要有新的灯安装的话,我还有修改代码(违反开闭原则)。我和灯之间的耦合太严重了。这样问题比较多。
于是建议我去看一下“命令模式”,让我和灯之间解耦,能否通过遥控器来控制灯的打开和关闭,并且这个遥控器还可以控制电视机的打开和关闭,空调的打开和关闭,让我可以专心做一个Boss,我只管发命令。
命令模式:将一个“请求”封装为一个对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。(动作Aciton模式)或(事务Transaction模式)
命令模式可以让请求发送者和接受者完全解耦,发送者与接受者之间没有直接的引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成执行请求动作。
在命令模式中包含如下几个角色:
简单用代码描述:
public interface Command {
void execute();
}
public class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver){
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action();
}
}
public class Receiver {
public void action(){
//业务处理
}
}
public class Invoker {
private Command command;
//构造注入
public Invoker(Command command){
this.command = command;
}
//设值注入
public void setCommand(Command command) {
this.command = command;
}
public void doString(){
command.execute();
}
}
命令模式的本质是对请求的封装,一个请求对应于一个命令(比如一个开灯请求,对应一个开灯的命令),将发出命令的责任和执行命令的责任分开!
从上面看,命令模式是根据抽象命令编程,只有实现了抽象命令类的具体命令才能与请求接收者关联。
通过对象命令模式的简单学习,改造之前设计的开灯方式,现在使用一个遥控器,让遥控器帮Boss完成任务,Boss只需要下达命令即可,并且能够实现返回上一次执行的操作,即撤销功能。
//抽象接口命令
public interface Command {
//执行操作
void execute();
//撤销操作
void undo();
}
//具体命令对象
public class LightOffCommand implements Command{
private Light light;
//通过set设值
public void setLight(Light light){
this.light = light;
}
@Override
public void execute() {
light.open();
}
@Override
public void undo() {
light.close();
}
}
//具体命令对象
public class LightOnCommand implements Command {
private Light light;
//通过set设值
public void setLight(Light light){
this.light = light;
}
@Override
public void execute() {
light.open();
}
@Override
public void undo() {
light.close();
}
}
public interface Light {
void open();//打开
void close();//关闭
}
//请求实际的执行者 Receiver
public class KuXuanLight implements Light{
private String name = "酷炫的灯";
@Override
public void open(){
System.out.println("---打开--" + this.name );
}
@Override
public void close(){
System.out.println("---关闭--" + this.name );
}
}
//相当于Invoker ,这个遥控器是语音智能的遥控器
public class RemoteControl {
private Command onCommand;
private Command offCommand;
private Command onDoCommand;
public RemoteControl(Command onCommand,Command offCommand){
this.onCommand = onCommand;
this.offCommand = offCommand;
}
public void onButtonPress(){
onDoCommand = onCommand;
onCommand.execute();
}
public void offButtonPress(){
onDoCommand = offCommand;
offCommand.execute();
}
public void onDoButtonPress(){
onDoCommand.undo();
}
}
//老板
public class Boss {
private String name;
//这是一个智能的遥控器,老板可以通过say的方式发起命令
private RemoteControl remoteControl;
public Boss(String name){
super();
this.name = name;
}
public void setRemoteControl(RemoteControl remoteControl){
this.remoteControl = remoteControl;
}
public void sayOpenLight(){
System.out.println("----晚上了,天黑了,准备开灯---");
remoteControl.onButtonPress();
System.out.println("----开灯完成---");
}
public void sayCloseLight(){
System.out.println("----下班了,准备关灯---");
remoteControl.offButtonPress();
System.out.println("----关灯完成---");
}
public void sayReturnLight(){
System.out.println("----刚才操作错误,撤销操作---");
remoteControl.onDoButtonPress();
System.out.println("----撤销完成---");
}
}
public class Test {
public static void main(String[] args) {
Light light = new KuXuanLight();
LightOnCommand onCommand = new LightOnCommand();
onCommand.setLight(light);
LightOffCommand offCommand = new LightOffCommand();
offCommand.setLight(light);
Boss boss = new Boss("专门下达命令的奶茶店老板");
RemoteControl remoteControl = new RemoteControl(onCommand,offCommand);
boss.setRemoteControl(remoteControl);
//天黑开灯,一定要开,因为不是黑店
boss.sayOpenLight();
//天还不太黑,还是先关了吧,可以使用撤销进行操作(这里是演示撤销功能)
boss.sayReturnLight();
System.out.println("================华丽的分割线================");
//天黑开灯,一定要开,因为不是黑店
boss.sayOpenLight();
//下班关灯,一定要关,因为不能浪费电,做新时代的好青年
boss.sayCloseLight();
}
}
----晚上了,天黑了,准备开灯---
---打开--酷炫的灯
----开灯完成---
----刚才操作错误,撤销操作---
---关闭--酷炫的灯
----撤销完成---
================华丽的分割线================
----晚上了,天黑了,准备开灯---
---打开--酷炫的灯
----开灯完成---
----下班了,准备关灯---
---关闭--酷炫的灯
----关灯完成---
此时请求者和执行者完全解耦,老板只需要通过语音发起命令,然后不用管正在的执行者是谁。
比如有一天设计模式MM偷偷把KuXuanLight,换成KuXuanDiaoBoLight,Boss的我也不用管,依旧发起命令即可!
public class KuXuanDiaoBoLight implements Light {
private String name = "酷炫碉堡了的五彩斑斓的灯";
@Override
public void open(){
System.out.println("---打开--" + this.name );
}
@Override
public void close(){
System.out.println("---关闭--" + this.name );
}
}
//只要改下下面这一行即可
Light light = new KuXuanDiaoBoLight();
目前是这个智能遥控器智能控制一个灯,如果想控制多个功能开关的话,只需要将遥控器里的命令改为如下格式:
private Command onCommand;
private Command offCommand;
public RemoteControl(Command onCommand,Command offCommand){
this.onCommand = onCommand;
this.offCommand = offCommand;
}
// --->>>改为--->>>>
private Command[] onCommand;
private Command[] offCommand;
int initSolt = 1;//遥控器有功能位
public RemoteControl(){
onCommand = new Command[initSolt];
offCommand = new Command[initSolt];
}
public eetRemoteControl(int slot,Command onCommand,Command offCommand){
onCommand[slot] = onCommand;
this.offCommand[slot] = offCommand;
}
//撤销可以使用Stack ,多次撤销操作-这里不进行说明了
通过对命令的修炼,发现命令还有一些其他的功能,如可以使用宏命令,说简单一点,就是可以发起一次请求可以执行发个操作!
比如奶茶店的遥控器有个功能是“Party”模式,那么按了这个按钮就会进行
- 打开彩灯
- 打开音响,播放音乐
- 奶茶店喷雾
那么这一系列的操作可以放到一个宏命令中进行执行
public class MacroCommand implements Command{
Command[] partyOn = {"开彩灯命令","开音响命令","开喷雾命令"};
Command[] partyOn = {"","",""};//对应的关闭命令
//这里使用简写,实际上可以使用set方式设置
}
这样就完成了一个宏命令的执行过程!
还有命名模式可以实现队列请求;
工作的队列和计算的线程直接完全是解耦的,比如这个线程这一刻在处理财务运算,下一刻可能就处理读取网络数据了。
还有命名模式可以实现请求日志,请求日志可以看:
6 请求日志
命令模式是一种使用频率非常高的设计模式,它可以将请求发送者与接收者解耦,请求发送者通过命令对象来间接引用请求接收者,使得系统具有更好的灵活性和可扩展性。
优点
降低系统的耦合度。由于请求者与接收者之间不存在直接引用,因此请求者与接收者之间实现完全解耦,相同的请求者可以对应不同的接收者,同样,相同的接收者也可以供不同的请求者使用,两者之间具有良好的独立性。
新的命令可以很容易地加入到系统中。由于增加新的具体命令类不会影响到其他类,因此增加新的具体命令类很容易,无须修改原有系统源代码,甚至客户类代码,满足“开闭原则”的要求。
可以比较容易地设计一个命令队列或宏命令(组合命令)。
为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案。
缺点
适用场景
在以下情况下可以考虑使用命令模式:
系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者无须知道接收者的存在,也无须知道接收者是谁,接收者也无须关心何时被调用。
系统需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调用者可以有不同的生命期,换言之,最初的请求发出者可能已经不在了,而命令对象本身仍然是活动的,可以通过该命令对象去调用请求接收者,而无须关心请求调用者的存在性,可以通过请求日志文件等机制来具体实现。
系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
系统需要将一组操作组合在一起形成宏命令。
上面总结全部来源:8 命令模式总结
一、设计模式-开篇—为什么我要去旅行? #和设计模式一起旅行#
二、设计模式-必要的基础知识—旅行前的准备 #和设计模式一起旅行#
三、设计模式介绍—她是谁,我们要去哪里? #和设计模式一起旅行#
四、单例模式—不要冒充我,我只有一个! #和设计模式一起旅行#
五、工厂模式—旅行的钱怎么来 #和设计模式一起旅行#
六、策略模式—旅行的交通工具 #和设计模式一起旅行#
七、观察者模式——关注我,分享旅途最浪漫的瞬间! #和设计模式一起旅行#
八、装饰者模式—巴厘岛,奶茶店的困扰! #和设计模式一起旅行#
九、命令模式—使用命令控制奶茶店中酷炫的灯 #和设计模式一起旅行#
十、模板方法模式—制作更多好喝的饮品! #和设计模式一起旅行#
十一、代理模式 —专注,做最好的自己!#和设计模式一起旅行#
十二、适配器模式——解决充电的烦恼 #和设计模式一起旅行#
十三、外观模式—— 简化接口 #和设计模式一起旅行#
十四、迭代器模式—— 一个一个的遍历 #和设计模式一起旅行#
十五、组合模式—— 容器与内容的一致性 #和设计模式一起旅行#
十六、状态模式—用类表示状态 #和设计模式一起旅行#
十七、访问者模式-访问数据结构并处理数据 #和设计模式一起旅行#
十八、职责链模式-推卸责任,不关我的事,我不管!#和设计模式一起旅行#
十九、原型模式—通过复制生产实例 #和设计模式一起旅行#
二十、设计模式总结—后会有期 #和设计模式一起旅行#
如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到,谢谢!
如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
祝你今天开心愉快!
欢迎访问我的csdn博客,我们一同成长!
不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!
博客首页 : http://blog.csdn.net/u010648555