命令模式定義
命令模式將請求封裝成對象,以便使用不同的請求、隊列或者日志來參數化其他對象,命令模式支持可撤銷的操作。
命令模式可以對發送者和接受者完全解耦,發送者和接收者之間沒有直接的聯系,發送者只需要知道如何發送請求,不需要關心請求如何完成,這就是命令模式,命令模式將方法的調用給封裝起來了。
命令模式結構
image
說明:上圖中的Command:抽象命令類,ConcreteCommand:具體命令類,Invoker:調用者,Receiver:接受者,Client:客戶類。命令的模式本質就在于將命令進行封裝,將發出的命令測責任和執行命令的責任分開,發送者只需要知道如何發送指令即可,不需要知道命令如何實現的,甚至執行是否成功都不需要知道,命令模式將請求也變為一個對象,它和其他對象一樣可以被存儲和傳遞。
命令模式的實現
在這里,我們以電視機為例,電視劇是請求的接受者,遙控器是請求的發送者,遙控器上有一些按鈕,不同的按鈕對應不同的操作,在這里遙控器需要執行三個命令,打開電視,關閉電視,換臺。
類圖結構如下
image
抽象命令接口
/**
* 命令接口,為所有的命令聲明一個接口
*@author lky
*@date 2018年1月19日
*/
public interface Command {
public void excute();
}
電視機類
/**
* 電視機類
*@author lky
*@date 2018年1月19日
*/
public class Telvision {
public void open(){
System.out.println("打開電視機....");
}
public void close(){
System.out.println("關閉電視機....");
}
public void changeChannel(){
System.out.println("切換電視機頻道....");
}
}
遙控器類
/**
* 遙控器類
*@author lky
*@date 2018年1月19日
*/
public class Controller {
private Command openTvCommand;
private Command closeTvCommand;
private Command changeTvCommand;
public Controller(Command openTvCommand, Command closeTvCommand,
Command changeTvCommand) {
super();
this.openTvCommand = openTvCommand;
this.closeTvCommand = closeTvCommand;
this.changeTvCommand = changeTvCommand;
}
public void open(){
openTvCommand.excute();
}
public void close(){
closeTvCommand.excute();
}
public void change(){
changeTvCommand.excute();
}
}
遙控器的打開按鈕類
/**
* 遙控器的打開電視按鈕
*@author lky
*@date 2018年1月19日
*/
public class OpenTvCommand implements Command{
private Telvision tv;
public OpenTvCommand() {
tv = new Telvision();
}
@Override
public void excute() {
tv.open();
}
}
遙控器的換臺按鈕
/**
* 遙控機換臺按鈕
*@author lky
*@date 2018年1月19日
*/
public class ChangeTvCommand implements Command{
private Telvision tv;
public ChangeTvCommand() {
tv = new Telvision();
}
@Override
public void excute() {
tv.changeChannel();
}
}
遙控器的關閉按鈕
public class CloseTvCommand implements Command{
private Telvision tv;
public CloseTvCommand() {
tv = new Telvision();
}
@Override
public void excute() {
tv.close();
}
}
客戶端
public class Client {
public static void main(String[] args) {
Command openCommand,closeCommand,changeCommand;
openCommand = new OpenTvCommand();
closeCommand = new CloseTvCommand();
changeCommand = new ChangeTvCommand();
Controller controller = new Controller(openCommand, closeCommand, changeCommand);
controller.open();
controller.change();
controller.close();
}
}
輸出結果
打開電視機....
切換電視機頻道....
關閉電視機....
為方便理解,將代碼放在一起
[圖片上傳失敗...(image-3e5f5e-1519534651204)]
命令模式的優缺點
- 降低了系統的耦合度
- 新的命令可以很容易的添加進去
- 使用命令模式可能會導致某些系統有過多的具體命令類
命令模式的使用場景
- 系統需要請求調用者和請求接受者解耦,使得調用者和接收者不會直接交互
- 系統需要在不同的時間指定請求,將請求排隊和執行請求
- 系統需要支持命令的插銷和恢復操作
- 系統需要將一組操作組合在一起
總結
- 命令模式的本質是將命令對象進行封裝打包,將發出的命令的責任和執行命令的責任進行分割開。
- 命令模式中發送者只需要知道如何發送命令,無需關心命令執行的具體過程。
- 在發送者和接受者兩者之間是通過命令對象進行溝通的,請求命令本身就當做一個對象在兩者之間進行傳遞,他封裝了接受者和一組動作。
- 命令模式支持撤銷操作。
- 命令模式隊列請求和日志請求。