先看需求:设计一个家电遥控器系统,每个家电由开、关两个按钮控制, 每个家电都由各自的厂商提供了实现方法,我们只需要调用这些方法即可,如图所示:
如何实现这个功能呢?
第一步我们要排除的实现方式就是if条件判断,因为一旦增加家电,我们就必须修改代码,这不符合我们的设计思路。
然后我们想想,遥控按钮只是发出一个请求,具体的实现是通过各自厂商的api,我们应该让遥控器(动作的请求者)从厂商的api(动作的执行者)中解耦出来。可是怎么去解耦呢?毕竟按钮动作和家电行为是息息相关的。
这个时候就可以使用命令模式,来认识一下命令模式。
先看定义:命令模式是把一个操作或者行为抽象为一个对象中,通过对命令的抽象化来使得发出命令的责任和执行命令的责任分隔开。命令模式的实现可以提供命令的撤销和恢复功能
听着还是很抽象,我们再举一个例子,《破产姐妹》中熟悉的场景 ,顾客到餐厅点单,服务员max拿了订单,放在订单柜台,厨师oleg根据订单准备餐点。
分析下其中的过程,把订单想象成一个用来请求准备餐点的对象,订单对象可以被传递,服务员max负责传递对象,订单的接口中只包含一个orderup()方法,这个方法封装了而准备餐点所需的动作,订单内有一个“需要进行准备工作的对象”(也就是厨师oleg)的引用,这一切都封装起来,max甚至不需要知道订单上有什么,她只负责传递。
有没有清楚一些,转成类图:
类图中可以看出,其中的几个角色:
命令接口:
//命令接口 public interface command { //命令方法 void execute(); }
命令接收者
//命令接收者(receiver),电灯 public class light { private string name; public light(string name){ this.name=name; } //开灯操作 public void on(){ system.out.println(name+":开灯!"); } //关灯操作 public void off(){ system.out.println(name+":关灯"); } }
绑定命令与接收者关系
//绑定命令与接收者关系conretecommand public class lightoncommand implements command { light light; public lightoncommand(light light){ this.light=light; } //具体命令方法 public void execute() { light.on(); } }
调用者(invoker)
//命令模式的客户(invoker) public class simpleremotecontrol { //命令接口 command solt; public void setcommand(command command){ this.solt=command; } //命令方法 public void buttonwaspressed(){ solt.execute(); } }
运行:
private static void simplecontrol() { //遥控器调用者 simpleremotecontrol control=new simpleremotecontrol(); //电灯 light light=new light("客厅"); //具体命令类 lightoncommand lightoncommand=new lightoncommand(light); //设置命令 control.setcommand(lightoncommand); //命令方法 control.buttonwaspressed(); }
结果:
这里其实只实现了其中一个按钮,让我们来补充一些代码
增加多一个接收者:
//另外一个接受者吊灯 public class ceilingfan { private string name; public ceilingfan(string name){ this.name=name; } public void on(){ system.out.println(name+":打开"); } public void off(){ system.out.println(name+":关闭"); } }
//吊灯的开灯命令 public class ceilingfanoffcommand implements command { ceilingfan ceilingfan; public ceilingfanoffcommand(ceilingfan ceilingfan){ this.ceilingfan=ceilingfan; } //具体命令方法 public void execute() { ceilingfan.off(); } } //吊灯的关灯命令 public class ceilingfanoncommand implements command { ceilingfan ceilingfan; public ceilingfanoncommand(ceilingfan ceilingfan){ this.ceilingfan = ceilingfan; } //具体命令方法 public void execute() { ceilingfan.on(); } }
调用者遥控:
//遥控调用 public class remotecontrol { //申明命令数组 command[] oncommands; command[] offcommands; public remotecontrol(){ oncommands=new command[4]; offcommands=new command[4]; } //设置命令 public void setcommand(int solt,command oncommand,command offcommand){ oncommands[solt]=oncommand; offcommands[solt]=offcommand; } //打开按钮 public void onbuttonwaspressed(int solt){ oncommands[solt].execute(); } //关闭按钮 public void offbuttonwaspressed(int solt){ offcommands[solt].execute(); } }
实际操作遥控:
private static void control() { remotecontrol remotecontrol=new remotecontrol(); light roomlight=new light("客厅灯"); light kitchlight=new light("厨房灯"); ceilingfan roomceilingfan=new ceilingfan("客厅吊扇"); ceilingfan kitchceilingfan=new ceilingfan("厨房吊扇"); //电灯相关命令 lightoncommand roomlightoncommand=new lightoncommand(roomlight); lightoncommand kitchlightoncommand=new lightoncommand(kitchlight); lightoffcommand roomlightoffcommand=new lightoffcommand(roomlight); lightoffcommand kitchlightoffcommand=new lightoffcommand(kitchlight); //吊扇相关命令 ceilingfanoncommand roomceilingfanoncommand =new ceilingfanoncommand(roomceilingfan); ceilingfanoncommand kitchceilingfanoncommand =new ceilingfanoncommand(kitchceilingfan); ceilingfanoffcommand roomceilingfanoffcommand =new ceilingfanoffcommand(roomceilingfan); ceilingfanoffcommand kitchceilingfanoffcommand =new ceilingfanoffcommand(kitchceilingfan); //将命令加载到卡槽中 remotecontrol.setcommand(0,roomlightoncommand,roomlightoffcommand); remotecontrol.setcommand(1,kitchlightoncommand,kitchlightoffcommand); remotecontrol.setcommand(2,roomceilingfanoncommand,roomceilingfanoffcommand); remotecontrol.setcommand(3,kitchceilingfanoncommand,kitchceilingfanoffcommand); //使用遥控 remotecontrol.onbuttonwaspressed(0); remotecontrol.offbuttonwaspressed(0); remotecontrol.onbuttonwaspressed(1); remotecontrol.offbuttonwaspressed(1); remotecontrol.onbuttonwaspressed(2); remotecontrol.offbuttonwaspressed(2); remotecontrol.onbuttonwaspressed(3); remotecontrol.offbuttonwaspressed(3); }
运行结果:
在下面的情况下可以考虑使用命令模式:
优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
另附源码地址:
如对本文有疑问, 点击进行留言回复!!
【面试题】研究过tomcat的NioEndpoint源码吗?请阐述下Reactor多线程模型在tomcat中的实现。
荐 厉害了!阿里P8架构师用4大技术文档带你深入解读爆火的中台战略
网友评论