北風設計模式課程---29、命令模式
一、總結
一句話總結:
整體系統如何初始做好設計,會非常節約時間,而無需管事大型項目還是小型項目,無需管事面向過程還是面向對象
命令模式就是封裝了類的調用:一個類的命令列表里面存各種類,然后遍歷調用這些類的方法
1、如果中小型項目的結構通過MVC本身就比較清晰了,還有必要過度使用設計模式么?
沒必要:設計模式雖然讓代碼更加工整了,但是也增加了很多類和很多代碼,不一定划得來
面向過程轉面向對象也很容易。重構一下代碼就好。然后可以按照需求增加這些設計模式。
整體系統如何初始做好設計,會非常節約時間,而無需管事大型項目還是小型項目,無需管事面向過程還是面向對象
2、面向對象編程和面向過程編程?
照我看來,黑貓白貓,能抓到老鼠的就是好貓。面向過程配上mvc在中小型項目中也是夠用的。
面向過程轉面向對象也很容易。重構一下代碼就好。然后可以按照需求增加這些設計模式。
整體系統如何初始做好設計,會非常節約時間,而無需管事大型項目還是小型項目,無需管事面向過程還是面向對象
初始建議面向對象編程,結構清晰,不易出錯,反而會節約時間的
3、什么是命令模式?
Command模式通過被稱為Command的類封裝了對目標對象的調用行為以及調用參數。
Command模式也叫命令模式 ,是行為設計模
式的一種。Command模式通過被稱為
Command的類封裝了對目標對象的調用行為以
及調用參數。
4、在面向對象的程序設計中,一個對象調用另一個對象,一般情況下的調用過程是怎樣的?
1、創建目標對象實例;設置調用參數;調用目標對象的方法。
2、命令模式:但在有些情況下有必要使用一個專門的類對這種調用過程加以封裝,我們把這種專門的類稱作command類。
5、命令模式的應用場景?
- 整個調用過程比較繁雜,或者存在多處這種調用。這時,使用Command類對該調用加以封裝,便於功能的再利用。
- 調用前后需要對調用參數進行某些處理。
- 調用前后需要進行某些額外處理,比如日志,緩存,記錄歷史操作等。
6、命令模式 實例?
有賣蘋果命令類,有賣香蕉命令類。小商販Peddler類封裝了賣蘋果和賣香蕉命令。有服務員Waiter類,里面有命令列表數據結構,有添加命令和刪除命令方法,也有sail方法就是一次調用蘋果或香蕉命令類的sail方法。
7、命令模式的角色和職責?
1、Command:Command抽象類。Command.java
2、ConcreteCommand:Command的具體實現類。AppleCommand.java;BananaCommand.java
3、Receiver:需要被調用的目標對象。Peddler.java
4、Invorker:通過Invorker執行Command對象。Waiter.java
二、內容在總結中
1、相關知識
ConcreteCommand:Command的具體實現類。AppleCommand.java;BananaCommand.java
Receiver:需要被調用的目標對象。Peddler.java
Invorker:通過Invorker執行Command對象。Waiter.java
2、代碼
Command:Command抽象類。Command.java
package com.ibeifemg.ex4; public abstract class Command { private Peddler peddler; public Command(Peddler peddler) { this.peddler = peddler; } public Peddler getPeddler() { return peddler; } public void setPeddler(Peddler peddler) { this.peddler = peddler; } public abstract void sail(); }
ConcreteCommand:Command的具體實現類。
AppleCommand.java;
package com.ibeifemg.ex4; public class AppleCommand extends Command { public AppleCommand(Peddler peddler) { super(peddler); } public void sail() { this.getPeddler().sailApple(); } }
BananaCommand.java
package com.ibeifemg.ex4; public class BananaCommand extends Command{ public BananaCommand(Peddler peddler) { super(peddler); } public void sail() { this.getPeddler().sailBanana(); } }
Receiver:需要被調用的目標對象。Peddler.java
package com.ibeifemg.ex4; /* * 小商販 */ public class Peddler { //賣蘋果 public void sailApple() { System.out.println("賣蘋果"); } //賣香蕉 public void sailBanana() { System.out.println("賣香蕉"); } }
Invorker:通過Invorker執行Command對象。Waiter.java
package com.ibeifemg.ex4; import java.util.ArrayList; import java.util.List; public class Waiter { private List<Command> commands = new ArrayList<Command>(); public void setOrder(Command command) { commands.add(command); } public void removeOrder(Command command) { commands.remove(command); } public void sail() { for(Command command : commands) { command.sail(); } } }
客戶端調用:
package com.ibeifemg.ex4; public class MainClass { public static void main(String[] args) { Peddler peddler = new Peddler(); // peddler.sailApple(); // peddler.sailBanana(); Command appleCommand = new AppleCommand(peddler); Command bananaCommand = new BananaCommand(peddler); // appleCommand.sail(); // bananaCommand.sail(); Waiter waiter = new Waiter(); //下訂單 waiter.setOrder(appleCommand); waiter.setOrder(bananaCommand); //移除訂單某項 waiter.removeOrder(appleCommand); waiter.sail(); } }
三、java設計模式-----23、命令模式
轉自或參考:java設計模式-----23、命令模式
https://www.cnblogs.com/xiaobai1226/p/8651632.html
概念:
Command模式也叫命令模式 ,是行為設計模式的一種。Command模式通過被稱為Command的類封裝了對目標對象的調用行為以及調用參數。
命令模式(Command Pattern)是一種數據驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在對象中,並傳給調用對象。調用對象尋找可以處理該命令的合適的對象,並把該命令傳給相應的對象,該對象執行命令。
主要解決:
在軟件系統中,“行為請求者”與“行為實現者”通常呈現一種“緊耦合”。但在某些場合,比如要對行為進行“記錄、撤銷/重做、事務”等處理,這種無法抵御變化的緊耦合是不合適的。在這種情況下,如何將“行為請求者”與“行為實現者”解耦?將一組行為抽象為對象,實現二
者之間的松耦合。這就是命令模式(Command Pattern)。
下面,舉一個小例子,但不是使用命令模式實現的
新建一個Peddler類,是一個賣水果的小商販
1 /* 2 * 小商販 3 */ 4 public class Peddler { 5 /* 6 * 賣蘋果 7 */ 8 public void sailApple(){ 9 System.out.println("賣蘋果"); 10 } 11 12 /* 13 * 賣香蕉 14 */ 15 public void sailBanana(){ 16 System.out.println("賣香蕉"); 17 } 18 }
再建一個客戶端
1 public class MainClass { 2 public static void main(String[] args) { 3 Peddler peddler = new Peddler(); 4 peddler.sailApple(); 5 peddler.sailBanana(); 6 } 7 }
結果:
命令模式的應用場景
在面向對象的程序設計中,一個對象調用另一個對象,一般情況下的調用過程是:創建目標對象實例;設置調用參數;調用目標對象的方法(像剛才的例子MainClass中,創建Peddler實例,再調度其中的方法)。
但在有些情況下有必要使用一個專門的類對這種調用過程加以封裝,我們把這種專門的類稱作command類。
1、整個調用過程比較繁雜,或者存在多處這種調用。這時,使用Command類對該調用加以封裝,便於功能的再利用。
2、調用前后需要對調用參數進行某些處理。
3、調用前后需要進行某些額外處理,比如日志,緩存,記錄歷史操作等。
命令模式的結構
命令模式的角色和職責
1、Command:Command抽象類,定義命令的接口,聲明執行的方法。。
2、ConcreteCommand:Command的具體實現類,命令接口實現對象,是“虛”的實現;通常會持有接收者,並調用接收者的功能來完成命令要執行的操作。
3、Receiver:需要被調用的目標對象,接收者,真正執行命令的對象。任何類都可能成為一個接收者,只要它能夠實現命令要求實現的相應功能。
4、Invorker:通過Invorker執行Command對象,要求命令對象執行請求,通常會持有命令對象,可以持有很多的命令對象。這個是客戶端真正觸發命令並要求命令執行相應操作的地方,也就是說相當於使用命令對象的入口。
5、Client:創建具體的命令對象,並且設置命令對象的接收者。注意這個不是我們常規意義上的客戶端,而是在組裝命令對象和接收者,或許,把這個Client稱為裝配者會更好理解,因為真正使用命令的客戶端是從Invoker來觸發執行。
當然,我們的例子非常簡單,用不到命令模式,我們假設操作很復雜,用命令模式改造一下
首先,創建類對調用過程進行一個封裝,先創建一個Command抽象父類
1 public abstract class Command { 2 //包含一個Receiver的引用 3 private Peddler peddler; 4 5 public Command(Peddler peddler) { 6 super(); 7 this.peddler = peddler; 8 } 9 10 public Peddler getPeddler() { 11 return peddler; 12 } 13 14 public void setPeddler(Peddler peddler) { 15 this.peddler = peddler; 16 } 17 18 public abstract void sail(); 19 }
接下來創建ConcreteCommand,每一個操作都要創建一個,所以我們要創建兩個Apple與Banana
1 /* 2 * Apple 3 */ 4 public class AppleCommand extends Command{ 5 6 public AppleCommand(Peddler peddler) { 7 super(peddler); 8 } 9 10 @Override 11 public void sail() { 12 //還可以在這句話前后做額外的處理 13 this.getPeddler().sailApple(); 14 } 15 16 }
1 /* 2 * Banana 3 */ 4 public class BananaCommand extends Command{ 5 6 public BananaCommand(Peddler peddler) { 7 super(peddler); 8 } 9 10 @Override 11 public void sail() { 12 //還可以在這句話前后做額外的處理 13 this.getPeddler().sailBanana(); 14 } 15 16 }
最后,修改MainClass
1 public class MainClass { 2 public static void main(String[] args) { 3 Peddler peddler = new Peddler(); 4 Command appleCommand = new AppleCommand(peddler); 5 Command bananaCommand = new BananaCommand(peddler); 6 7 appleCommand.sail(); 8 bananaCommand.sail(); 9 10 } 11 }
但是這樣還不夠好,可以看到這是直接由命令來調用sail方法的,這樣不好,我們希望由專人來賣東西,就像人家請了一個服務員一樣,所以我們再新建一個Invorker
public class Waiter { private Command command; public Command getCommand() { return command; } public void setCommand(Command command) { this.command = command; } public void sail(){ command.sail(); } }
再修改客戶端
1 public class MainClass { 2 public static void main(String[] args) { 3 Peddler peddler = new Peddler(); 4 Command appleCommand = new AppleCommand(peddler); 5 Command bananaCommand = new BananaCommand(peddler); 6 7 Waiter waiter = new Waiter(); 8 waiter.setCommand(appleCommand); 9 waiter.sail(); 10 11 waiter.setCommand(bananaCommand); 12 waiter.sail(); 13 14 } 15 }
這樣Client就直接與Invorker進行通話
我們現在只能添加命令,卻不能移除命令,,而且一次只能有一個命令,我們繼續改造
1 public class Waiter { 2 private Map<String,Command> commands; 3 4 public Map<String, Command> getCommands() { 5 if(commands == null){ 6 commands = new HashMap<String,Command>(); 7 } 8 9 return commands; 10 } 11 12 public void setCommand(String key, Command command) { 13 if(commands == null){ 14 commands = new HashMap<String,Command>(); 15 } 16 commands.put(key, command); 17 } 18 19 public void RemoveCommand(String key) { 20 commands.remove(key); 21 } 22 23 public void sail(String key){ 24 commands.get(key).sail(); 25 } 26 }
Client
1 public class MainClass { 2 public static void main(String[] args) { 3 Peddler peddler = new Peddler(); 4 Command appleCommand = new AppleCommand(peddler); 5 Command bananaCommand = new BananaCommand(peddler); 6 7 Waiter waiter = new Waiter(); 8 waiter.setCommand("apple", appleCommand); 9 waiter.setCommand("banana", bananaCommand); 10 11 waiter.sail("apple"); 12 waiter.sail("banana"); 13 14 waiter.RemoveCommand("apple"); 15 16 } 17 }
這樣,就完成了,一個命令模式的例子
命令模式的優缺點
優點: 1、降低了系統耦合度。
2、新的命令可以很容易添加到系統中去。
缺點:使用命令模式可能會導致某些系統有過多的具體命令類。