目录
一、场景 1、文本编辑器并不是一个好的例子,设备控制器才是 2、设备控制器的demo
二、不用命令模式
三、使用命令模式
四、进一步思考 1、省略对Command的建模可以吗? 2、命令模式的价值
一、场景
脱离场景谈设计模式毫无意义。先有某种场景,然后大神们(GoF)对其进行建模,以实现高内聚低耦合。
1、文本编辑器并不是一个好的例子,设备控制器才是
看了不少讲命令模式的文章,举的例子基本都是文本编辑器。 然而,并没有揭示命令模式的精髓。反而让读者觉得命令模式像过度设计。 生活中,我们手机上会装一个设备控制器 ,里面既可以控制空调的开关,还可以控制电视的开关。我将通过这个例子来阐述命令模式到底解决了什么问题 。
2、设备控制器的demo
用户选择空调,并选择关闭:空调便关闭了。 用户选择电视机,并选择关闭:电视机便关闭了。
二、不用命令模式
1、代码
public class AirConditioner {
public void turnOn ( ) {
System . out. println ( "空调已开启" ) ;
}
public void turnOff ( ) {
System . out. println ( "空调已关闭" ) ;
}
}
public class Television {
public void turnOn ( ) {
System . out. println ( "电视已开启" ) ;
}
public void turnOff ( ) {
System . out. println ( "电视已关闭" ) ;
}
}
public class Application {
public static void main ( String [ ] args) {
AirConditioner airConditioner = new AirConditioner ( ) ;
Television television = new Television ( ) ;
Scanner scanner = new Scanner ( System . in) ;
while ( true ) {
String device = scanner. next ( ) ;
if ( device. equals ( "exit" ) ) {
break ;
}
String command = scanner. next ( ) ;
if ( device. equals ( "airConditioner" ) ) {
if ( command. equals ( "turnOn" ) ) {
airConditioner. turnOn ( ) ;
} else if ( command. equals ( "turnOff" ) ) {
airConditioner. turnOff ( ) ;
}
} else if ( device. equals ( "television" ) ) {
if ( command. equals ( "turnOn" ) ) {
television. turnOn ( ) ;
} else if ( command. equals ( "turnOff" ) ) {
television. turnOff ( ) ;
}
}
}
}
}
结果:
2、问题
随着发展,设备大概率不止空调和电视机,一旦增加新设备,客户端的代码就要有很大的改动。而且,每台设备能执行的命令也不止开启和关闭,一旦新增命令,又要修改客户端的代码。这都违背了“开闭原则”。 另外,各种设备的代码杂糅在一起,违背了“单一职责原则” 。
三、使用命令模式
1、代码
public interface Receiver {
void turnOn ( ) ;
void turnOff ( ) ;
}
public class AirConditioner implements Receiver {
@Override
public void turnOn ( ) {
System . out. println ( "空调已开启" ) ;
}
@Override
public void turnOff ( ) {
System . out. println ( "空调已关闭" ) ;
}
}
public class Television implements Receiver {
@Override
public void turnOn ( ) {
System . out. println ( "电视已开启" ) ;
}
@Override
public void turnOff ( ) {
System . out. println ( "电视已关闭" ) ;
}
}
public abstract class Command {
protected Receiver receiver;
public void setReceiver ( Receiver receiver) {
this . receiver = receiver;
}
public abstract void execute ( ) ;
}
public class TurnOffCommand extends Command {
@Override
public void execute ( ) {
receiver. turnOff ( ) ;
}
}
public class TurnOnCommand extends Command {
@Override
public void execute ( ) {
receiver. turnOn ( ) ;
}
}
public class DeviceManager {
private final Map < String , Receiver > devices;
private final Map < String , Command > commands;
private DeviceManager ( ) {
devices = ImmutableMap . of (
DeviceEnum . AIR_CONDITIONER . getValue ( ) , new AirConditioner ( ) ,
DeviceEnum . TELEVISION . getValue ( ) , new Television ( )
) ;
commands = ImmutableMap . of (
CommandEnum . TURN_ON . getValue ( ) , new TurnOnCommand ( ) ,
CommandEnum . TURN_OFF . getValue ( ) , new TurnOffCommand ( )
) ;
}
public static DeviceManager getSingleton ( ) {
return new DeviceManager ( ) ;
}
public void execute ( String device, String commandType) {
Receiver receiver = devices. get ( device) ;
Command command = commands. get ( commandType) ;
command. setReceiver ( receiver) ;
command. execute ( ) ;
}
}
public class Application {
public static void main ( String [ ] args) {
DeviceManager deviceManager = DeviceManager . getSingleton ( ) ;
Scanner scanner = new Scanner ( System . in) ;
while ( true ) {
String device = scanner. next ( ) ;
if ( device. equals ( "exit" ) ) {
break ;
}
String command = scanner. next ( ) ;
deviceManager. execute ( device, command) ;
}
}
}
2、当需求变化时
2.1 新增代码
public class StandByCommand extends Command {
@Override
public void execute ( ) {
receiver. standby ( ) ;
}
}
public interface Receiver {
. . .
void standby ( ) ;
}
public class Washer implements Receiver {
@Override
public void turnOn ( ) {
System . out. println ( "洗衣机已开启" ) ;
}
@Override
public void turnOff ( ) {
System . out. println ( "洗衣机已关闭" ) ;
}
@Override
public void standby ( ) {
System . out. println ( "洗衣机已待机" ) ;
}
}
public class AirConditioner implements Receiver {
. . .
@Override
public void standby ( ) {
System . out. println ( "空调已待机" ) ;
}
}
public class Television implements Receiver {
. . .
@Override
public void standby ( ) {
System . out. println ( "电视已待机" ) ;
}
}
public class DeviceManager {
private final Map < String , Receiver > devices;
private final Map < String , Command > commands;
private DeviceManager ( ) {
devices = ImmutableMap . of (
. . .
DeviceEnum . WASHER . getValue ( ) , new Washer ( )
) ;
commands = ImmutableMap . of (
. . .
CommandEnum . STAND_BY . getValue ( ) , new StandByCommand ( )
) ;
}
. . .
}
2.2 优点
之前写的代码,一行都没改动。只是通过新增代码,便实现了需求:
各个设备、各个命令都很单一,尽可能符合“单一职责”。
四、进一步思考
1、省略对Command的建模可以吗?
public class DeviceManager {
. . .
public void execute ( String device, String commandType) {
Device realDevice = deviceMap. get ( device) ;
realDevice. execute ( commandType) ;
}
. . .
}
public void execute ( String commandType) {
if ( "turnOn" . equals ( commandType) ) {
. . .
} else if ( "turnOff" . equals ( commandType) ) {
. . .
} else {
. . .
}
}
显然,去除对Command的建模后,代码变得冗余了。
2、命令模式的价值
当对真实场景建模后,各部分的交互逻辑如下图所示,便可以采用命令模式实现“高内聚、低耦合”的代码设计。