1. 概述
將一個請求封裝為一個對象(即我們創建的command對象),從而使你可用不同的請求對客戶進行參數化; 對請求排隊或記錄請求日志,以及支持可撤銷的操作。
2. 解決的問題
在軟件系統中,行為請求者與行為實現者通常是一種緊耦合的關系,但某些場合,比如需要對行為進行記錄、撤銷或重做、事務等處理時,這種無法抵御變化的緊耦合的設計就不太合適。
3. 模式中角色
3.1 抽象命令(command):定義命令的接口,聲明執行的方法。
3.2 具體命令(concretecommand):具體命令,實現要執行的方法,它通常是“虛”的實現;通常會有接收者,并調用接收者的功能來完成命令要執行的操作。
3.3 接收者(receiver):真正執行命令的對象。任何類都可能成為一個接收者,只要能實現命令要求實現的相應功能。
3.4 調用者(invoker):要求命令對象執行請求,通常會持有命令對象,可以持有很多的命令對象。這個是客戶端真正觸發命令并要求命令執行相應操作的地方,也就是說相當于使用命令對象的入口。
3.5 客戶端(client):命令由客戶端來創建,并設置命令的接收者。
4. 模式解讀
4.1 命令模式的類圖
4.2 命令模式的實現代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
/// <summary> /// 接收者類,知道如何實施與執行一個請求相關的操作,任何類都可能作為一個接收者。 /// </summary> public class receiver { /// <summary> /// 真正的命令實現 /// </summary> public void action() { console.writeline( "execute request!" ); } } /// <summary> /// 抽象命令類,用來聲明執行操作的接口 /// </summary> public interface icommand { void execute(); } /// <summary> /// 具體命令類,實現具體命令。 /// </summary> public class conceretecommand : icommand { // 具體命令類包含有一個接收者,將這個接收者對象綁定于一個動作 private receiver receiver; public conceretecommand(receiver receiver) { this .receiver = receiver; } /// <summary> /// 說這個實現是“虛”的,因為它是通過調用接收者相應的操作來實現execute的 /// </summary> public void execute() { receiver.action(); } } /// <summary> /// 調度類,要求該命令執行這個請求 /// </summary> public class invoker { private icommand command; /// <summary> /// 設置命令 /// </summary> /// <param name="command"></param> public void setcommand(icommand command) { this .command = command; } /// <summary> /// 執行命令 /// </summary> public void executecommand() { command.execute(); } } |
4.3 客戶端代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class program { static void main( string [] args) { receiver receiver = new receiver(); icommand command = new conceretecommand(receiver); invoker invoker = new invoker(); invoker.setcommand(command); invoker.executecommand(); console.read(); } } |
執行結果
4.4 模式分析
4.4.1 本質:對命令進行封裝,將發出命令與執行命令的責任分開。
4.4.2 每一個命令都是一個操作:請求的一方發出請求,要求執行一個操作;接收的一方收到請求,并執行操作。
4.4.3 請求方和接收方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是怎么被接收,以及操作是否被執行、何時被執行,以及是怎么被執行的。
4.4.4 使請求本身成為一個對象,這個對象和其它對象一樣可以被存儲和傳遞。
4.4.5 命令模式的關鍵在于引入了抽象命令接口,且發送者針對抽象命令接口編程,只有實現了抽象命令接口的具體命令才能與接收者相關聯。
5. 模式總結
5.1 優點
5.1.1 解除了請求者與實現者之間的耦合,降低了系統的耦合度。
5.1.2 對請求排隊或記錄請求日志,支持撤銷操作。
5.1.3 可以容易地設計一個組合命令。
5.1.4 新命令可以容易地加入到系統中。
5.2 缺點
5.2.1 因為針對每一個命令都需要設計一個具體命令類,使用命令模式可能會導致系統有過多的具體命令類。
5.3 適用場景
5.3.1 當需要對行為進行“記錄、撤銷/重做”等處理時。
5.3.2 系統需要將請求者和接收者解耦,使得調用者和接收者不直接交互。
5.3.3 系統需要在不同時間指定請求、請求排隊和執行請求。
5.3.4 系統需要將一組操作組合在一起,即支持宏命令。
6. 應用舉例:銀行帳號的存款、提款
6.1 類圖
6.2 代碼實現
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
/// <summary> /// 銀行帳號 /// </summary> public class account { /// <summary> /// 帳號總金額 /// </summary> private decimal totalamount { get ; set ; } /// <summary> /// 存錢 /// </summary> /// <param name="amount"></param> public void moneyin( decimal amount) { this .totalamount += amount; } /// <summary> /// 取錢 /// </summary> /// <param name="amount"></param> public void moneyout( decimal amount) { this .totalamount -= amount; } public decimal gettotalamout() { return totalamount; } } public abstract class command { protected account account; public command(account account) { this .account = account; } public abstract void execute(); } /// <summary> /// 存款命令 /// </summary> public class moneyincommand : command { private decimal amount; public moneyincommand(account account, decimal amount) : base (account) { this .amount = amount; } /// <summary> /// 實現存錢命令 /// </summary> public override void execute() { account.moneyin(amount); } } /// <summary> /// 取款命令類 /// </summary> public class moneyoutcommand : command { private decimal amount; public moneyoutcommand(account account, decimal amount) : base (account) { this .amount = amount; } /// <summary> /// 實現取錢命令 /// </summary> public override void execute() { account.moneyout(amount); } } public class invoker { private command command; public void setcommand(command command) { this .command = command; } public void executecommand() { command.execute(); } } |
6.3 客戶端代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
class program { static void main( string [] args) { // 創建銀行帳號 account account = new account(); // 創建一個存入500元的命令 command commandin = new moneyincommand(account,500); // 創建一個調度者 bankaccount.invoker invoker = new bankaccount.invoker(); // 設置存錢命令 invoker.setcommand(commandin); // 執行 invoker.executecommand(); console.writeline( "the current amount is " + account.gettotalamout().tostring( "n2" )); // 再次存入500 command commandin2 = new moneyincommand(account, 500); invoker.setcommand(commandin2); invoker.executecommand(); console.writeline( "the current amount is " + account.gettotalamout().tostring( "n2" )); // 取出300 command commandout = new moneyoutcommand(account, 300); invoker.setcommand(commandout); invoker.executecommand(); console.writeline( "the current amount is " + account.gettotalamout().tostring( "n2" )); console.read(); } } |
執行結果
以上就是本文的全部內容,希望能給大家一個參考,也希望大家多多支持服務器之家。