命令模式的三大角色:
Command:命令接口
Receiver:命令的执行者
Invoker:命令的发送者
以遥控器给电视发送为例进行说明。
1)电视机接口(电视行业总有标准)
package com.cqs.pattern.command;
/**
* receiver角色:TV接口
* Created by cqs on 10/23/16.
*/
public interface TV {
void turnOn();//开机
void turnOff();//关机
void voiceUp();//音量加大
void voiceDown();//音量减小
void display();//播放某个频道
void channelUp();//上一个频道
void channelDown();//下一个频道
}
具体的电视:不同厂家可以有不同的实现
package com.cqs.pattern.command;
/**
* 具体的receiver类:三星电视
* Created by cqs on 10/23/16.
*/
public class SamsungTV implements TV{
private int channel = 1;
public void turnOn() {
System.out.println("三星电视打开");
}
public void turnOff() {
System.out.println("三星电视关闭");
}
public void voiceUp() {
System.out.println("三星电视音量加1");
}
public void voiceDown() {
System.out.println("三星电视音量减1");
}
public void display() {
System.out.println("三星电视播放频道" + channel);
}
public void channelUp() {
this.channel += 1;
}
public void channelDown() {
this.channel -= 1;
}
}
2)命令接口
package com.cqs.pattern.command;
/**
* 命令接口
* Created by cqs on 10/23/16.
*/
public interface Command {
void execute();
}
以及具体的接口命令
package com.cqs.pattern.command;
/**
* 具体的Command类:开机命令
* Created by cqs on 10/23/16.
*/
public class TurnOnCommand implements Command{
private TV tv;//其实command可以声明为抽象类,将TV属性在抽象类中声明
public TurnOnCommand(TV tv) {
this.tv = tv;
}
public void execute() {
tv.turnOn();
}
}
package com.cqs.pattern.command;
/**
* 具体的Command类:播放频道命令
* Created by cqs on 10/23/16.
*/
public class DisplayCommand implements Command{
private TV tv;//其实command可以声明为抽象类,将TV属性在抽象类中声明
public DisplayCommand(TV tv) {
this.tv = tv;
}
public void execute() {
tv.display();
}
}
package com.cqs.pattern.command;
/**
* 具体的Command类:关机命令
* Created by cqs on 10/23/16.
*/
public class TurnOffCommand implements Command{
private TV tv;
public TurnOffCommand(TV tv) {
this.tv = tv;
}
public void execute() {
tv.turnOff();
}
}
3)遥控器(Invoker)
package com.cqs.pattern.command;
/**
* 遥控器(Invoker角色)
* Created by cqs on 10/23/16.
*/
public class RemoteControl {
// protected Command command;
//
// public void setCommand(Command command) {
// this.command = command;
// }
//
// public void runCommand(){
// command.execute();
// }
public void runCommand(Command command){
command.execute();
}
}
PS:很多例子都是将Invoker按照注释那样实现,个人觉得这样实现的弊端为每次调用的runCommand方法的时候都必须调用setCommand方法,不仅麻烦而且容易出错。
4)测试类
package com.cqs.pattern.command;
/**
* 测试类
* Created by cqs on 10/23/16.
*/
public class CommandClient {
public static void main(String[] args) {
RemoteControl remoteControl = new RemoteControl();
TV samsungTV = new SamsungTV();
Command turnOnSam = new TurnOnCommand(samsungTV);
remoteControl.runCommand(turnOnSam);
//
Command displaySam = new DisplayCommand(samsungTV);
remoteControl.runCommand(displaySam);
Command turnOffSam = new TurnOffCommand(samsungTV);
remoteControl.runCommand(turnOffSam);
}
}
运行结果:
写完了,可以稍微总结下:
1)命令模式其实还是蛮繁琐的,但是其很大的优势就是将命令的发送方(Invoker)与命令的执行方(Receiver)实现了解藕,这通过命令接口(Command)来实现的。这对完全符合开闭原则的:比如需求变了,需要播放Sony电视,或者LG电视,那么只要添加对应的TV实现类,然后高层稍微修改接口对象的就可以使用了。
2)业务才是灵魂,没必要死套模式的标准,比如Command完全可以声明抽象类,减少冗余代码的开发。
最后懒得画UML图了,就找了一张图(若涉及侵权,联系我删除)