设计模式第6式:命令模式
创始人
2024-05-22 21:11:42
0

前言

命令模式关注这样一种场景:指令发布者无需关注指令是怎么执行的,只需要指定具体的执行者,具体的指令由执行者来完成。命令模式将指令发布动作和指令执行动作解耦。

我在刚开始学习命令模式的时候,比较困惑它的使用场景。它不像之前讲的工厂模式,观察者模式那样有明确的使用场景。其实可以将命令模式应用在这个场景就比较好理解了:软件项目经理不可能完成所有的开发任务,他将软件开发的不同阶段设置为不同的指令,比如软件设计指令、软件开发指令、软件测试指令,然后将不同的指令指定不同的人员。

正文

1、餐厅点单场景

我们以面向对象的思维来看真实的餐厅点单场景是什么样的:
1、顾客创建一个订单(createorder());
2、招待者拿走订单(takeOrder());放在后厨柜台,然后通知厨师备餐(orderUp());
3、厨师备餐出餐(doSomething(),output);

我们来分析其中的角色:
1、把订单想象成封装了备餐请求的对象,对象是可以传递的。订单接口只包含一个方法orderUp(),这个方法封装备餐需要的所有动作。订单实现类内有一个厨师的引用。这些都被封装起来,所以招待者不需要知道订单上有什么,也不需要谁来备餐。
2、招待者的工作只是接受订单,然后调用订单的orderUp方法。
3、厨师具有备餐的技能。厨师和招待者是完全解耦的。

将以上场景进行抽象成命令模式,那这个模式的核心就是将“发出请求的对象”和“接受与执行请求的对象”解耦。

2、将餐厅抽象成命令模式

我们重新来讲命令模式:
在这里插入图片描述
三个角色:
1、调用者:发起命令的角色;
2、命令:封装执行者及其方法;
3、执行者:真正的动作实施人;

3、实现命令模式

上面讲了一堆,我们来实际写一个命令模式。首先,我们需要一个命令类接口,接口很简单,只有一个执行方法。

public interface Command {void execute();
}

然后,实现一个打开电灯的具体命令类。

public class LightOnCommand implements Command {Light light; // 命令类持有接受者的引用public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {  // 封装了接受者的一系列方法light.on(); // 这里可以编排多个方法}
}

命令对象持有了一个接受者,它是实际干活的。

public class Light {public void on() {sout("打开灯");}
}

有了命令类后,我们来看怎么使用它。我们来创建一个调用者。

public class Controller {Command command; // 持有一个命令对象public void setCommand(Command command) { // 可设置具体命令对象this.command = command;}public void pressButton() { // 调用者按下按钮就能发起命令command.execute(); // 调用命令对象封装好的方法}
}

最后,我们来验证一下调用者怎么执行。

public class Test {main() {Controller contr = new Controller();Light light = new Light();LightCommand lightcomm = new LightCommand(light); //命令封装了接受者和一系列实现动作contr.setCommand(lightcomm); // 调用者配置命令contr.pressButton(); // 调用者执行方法}
}

4、怎么理解“命令”

通过上面这个简单的例子,已经完整展示了命令模式的全貌。如果没有“命令”这个类,那么上面这个例子将是什么样的呢?那么调用者将要直接面对千百个功能复杂的接受者,调用者将要创建出多个接受者,并排列组合一系列方法。这会导致调用者类非常复杂,难以维护,后续改变功能或新增功能都要改动调用者。

现在使用命令模式后,将调用者和接受者解耦开,调用者只关注要给谁下命令,由具体的命令对象来编排众多调用者及其方法。

那么怎么理解“命令”呢?万物皆对象,“命令”首先是一个对象,它做了什么呢?它的重点工作就是编排功能,它可以持有真正执行动作的对象,然后在execute()方法中编排方法。

上面的案例中,调用者按下按钮就会打开灯,如果我想改变按钮的功能呢?比如改成关灯,或者先关灯再拉窗帘。这种情况下,调用者Controller的代码是不用改动的,我们要做的是新增命令类,然后在命令类的execute()方法中改成调用执行者的关灯方法,或者先调关灯方法再调拉窗帘方法。这样就真正做到了对修改关闭,对扩展开放。

5、命令模式在Java中的应用

Java中的线程类Thread就是使用命令模式的典型案例。线程启动的方法是Thread.start(),线程具体做什么事Thread类不关心,是在Runnable接口的run()方法中实现的。

类比上面讲的例子,Thread类就是调用者,它只管调用start()方法来启动线程,线程做什么由命令来执行;Runnable接口就是命令类Command,里面的run()方法就是命令类的execute()方法,具体执行什么由Runnable的实现类进行实现。这样一来,Thread类永远不用变化,试想一下如果Thread类需要改变,它怎么作为JDK中的工具类供大家使用。

总结

命令模式常用于解耦动作发起者和动作执行者,并提供了编排动作的功能。

我一开始学习设计模式的时候,容易分不清“客户端”是谁。比如命令模式中我会认为调用者Controller是“客户端”,观察者模式中的主题Subject是“客户端”。之所以会这样认为,是因为它们中有一个触发动作的方法,比如Controller中按按钮动作,主题Subject中发布事件的方法。其实它们是作为各自模式的一部分,只是它们作为门面直接面向了客户端,真正的客户端应该是调用它们的类。有没有发现,很多设计模式的目标就是保持这个门面代码不用修改,去扩展门面后面的类。

相关内容

热门资讯

读书节主持词 读书节主持词(精选15篇)  主持词要注意活动对象,针对活动对象写相应的主持词。现今社会在不断向前发...
宫崎骏《起风了》动漫的经典台... 宫崎骏《起风了》动漫的经典台词  台词(part/dialog/line)是戏剧表演中角色所说的话语...
婚礼回门答谢宴主持词 婚礼回门答谢宴主持词  尊敬的各位领导、各位来宾、朋友们,  大家中午好!  阳光明媚,歌声飞扬,欢...
重阳节精彩致辞 重阳节精彩致辞范文(通用7篇)  在平时的学习、工作或生活中,大家或多或少都用到过致辞吧,致辞受场合...
学校班级家长会主持词 学校班级家长会主持词  主持词要把握好吸引观众、导入主题、创设情境等环节以吸引观众。在如今这个时代,...
体操比赛主持词 关于体操比赛主持词4篇  主持词要根据活动对象的不同去设置不同的主持词。在如今这个中国,主持人在活动...
中学心理剧大赛主持词 中学心理剧大赛主持词  开幕  雪和华:亲爱的各位领导、各位老师、各位同学,大家晚上好!  雪:我是...
《网购奇遇》的经典台词 《网购奇遇》的经典台词  1、生命不息,扰民不止  2、你那个培训班办的,六年就一个学员还是你媳妇 ...
婚礼男方致辞 婚礼男方致辞婚礼男方致辞尊敬的各位来宾:大家好!今天是我与××小姐结婚的大好日子!我感到十分地高兴同...
结婚单位领导致辞 结婚单位领导致辞(通用18篇)  在平时的学习、工作或生活中,要用到致辞的地方还是很多的,致辞具有能...
《天若有情》里的经典台词 《天若有情》里的经典台词  1 如果他们只是单纯的男人和女人,他们能相爱吗?  2 偷东西 是罪恶的...
《黑执事》经典台词 《黑执事》经典台词  1、一旦拒绝了信仰,就不能再踏入神的大门。  2、那是必须的,,不管何时,王只...
风雨哈佛路经典台词 风雨哈佛路经典台词  引导语:《风雨哈佛路》这部影片相信很多人都看过,亦是一部非常好看的影片,那么有...
文艺节目主持词 文艺节目主持词四篇  主持词要把握好吸引观众、导入主题、创设情境等环节以吸引观众。在一步步向前发展的...
幼儿园六一儿童节主持词 幼儿园六一儿童节主持词尊敬的各位来宾、各位朋友大家下午好!沐浴着和风丽日,我们即将迎来花团锦簇、芳香...
教师节表彰大会校长的致辞 教师节表彰大会校长的致辞范文(精选6篇)  在平平淡淡的日常中,要用到致辞的地方还是很多的,致辞讲求...
婚礼开场白主持词 婚礼开场白主持词  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。随着社会一步步向前发展...
会主持人开场白台词 会主持人开场白台词2013年会主持人开场白台词    甲:新年的钟声即将敲响,时光的车轮又留下了一道...
领导主持词 领导主持词三篇  主持词已成为各种演出活动和集会中不可或缺的一部分。在现今人们越来越重视活动氛围的社...
升学宴致辞 升学宴致辞(精选15篇)  在现实生活或工作学习中,大家一定都接触过致辞吧,致辞具有“礼仪性”或“仪...