首先,我们需要思考一下为什么要用命令模式。命令模式可以让调用者和执行者之间解耦,调用者无需知道是如何执行的,只用告诉执行者可以执行了,执行者完成执行就行了。
那么如何做到这一点呢?假设我们有一个遥控器,有多个插槽,每个插槽可以控制多个东西的开关,比如电灯,房门,电视等等。以往我们的做法是,新建一个电灯遥控器类RemoteControl,当遥控器按下时,写if else判断是电灯还是房门还是电视,然后调用相关的on或off方法即可。是不是觉得这样完全没有违和感?但这样有一个问题是,所有代码都需要写在RemoteControl里,这样就会有一堆if else的判断,如果又有新的东西需要加进遥控器里,就必须要修改这个类的代码。
而命令模式的做法是,首先新建一个Command接口,接口里只有execute方法。
现在电灯有开(on)和关(off)两个方法,也就是两个命令,我们把这两个命令单独拿出来成为两个类LightOnCommand,LightOffCommand,实现Command接口。然后execute方法里调用电灯类Light的开关方法。在遥控器类RemoteControl里只和Command打交道,具体来说就是在RemoteControl里持有Command对象,我们有一个SetCommand方法可以设定Command。也就让遥控器和电灯解耦了。这样如果我们需要将房门开关的功能加到遥控器里时,我们不需要修改之前的代码,只用再新建房门开关的两个类DoorOpenCommand,DoorCloseCommand即可。这样就遵守了开放(易于扩展)封闭(不修改原来的代码)原则。
命令模式的好处还不止这些,它可以让你动态的改变Command,比如现在遥控器的第一个插槽里放的是电灯的开关,在不修改代码的前提下,我可以很轻易的通过setCommand方法来改变它为房门的开关。
另外,命令模式还支持撤消动作。这个在实际中也有很多应用,比如服务器通过日志恢复宕机前的所有操作,听起来很神奇,其实也很简单,就是在执行命令时在日志里记录下执行的命令即可。你们可能会说,这个例子和撤消有什么关系?撤消,说白了,也是要记录上一次执行的命令,点击撤消时,把记录好的命令执行一次就行了。所以本质上是一样的。