目录 一、场景 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、命令模式的价值
当对真实场景建模后,各部分的交互逻辑如下图所示,便可以采用命令模式实现“高内聚、低耦合”的代码设计。