外觀模式(Facade)
「外觀模式(Facade)」又叫「門面模式」。
即使沒有聽過「外觀模式」,也很有可能常常用,因為它完美地體現了「依賴倒轉原則」和「迪米特法則」的思想
外觀模式(Facade)結構
Fancade外觀類別:知道哪些子系統類負責處理請求,將客戶的請求代理給適當的子系統物件。SubSystem Classes子系統類別集合:實現子系統的功能,處理Fancade物件指派的任務。
注意:子類別中沒有
Fancade的任何資訊,就沒有對Fancade物件的引用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Client
Fancade 外觀類別:知道哪些子系統類負責處理請求,將客戶的請求代理給適當的子系統物件
+ MethodA()
+ MethodB()
SubSystem Classes
SubSystem1
+ MethodOne()
SubSystem2
+ MethodOne()
SubSystem3
+ MethodOne()
SubSystem4
+ MethodOne()
四個子系統的類別
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class SubSystem1 {
public void MethodOne() {
Console.WriteLine("子系統1的方法");
}
}
class SubSystem2 {
public void MethodOne() {
Console.WriteLine("子系統2的方法");
}
}
class SubSystem3 {
public void MethodOne() {
Console.WriteLine("子系統3的方法");
}
}
class SubSystem4 {
public void MethodOne() {
Console.WriteLine("子系統4的方法");
}
}
外觀類別
外觀類別,它需要瞭解所有的子系統的方法或屬性,進行組合,以備外界調用。
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
class Facade {
SubSystem1 s1;
SubSystem2 s2;
SubSystem3 s3;
SubSystem4 s4;
public Facade() {
s1 = new SubSystem1();
s2 = new SubSystem2();
s3 = new SubSystem3();
s4 = new SubSystem4();
}
public void MethodA() {
s1.MethodOne();
s3.MethodOne();
s4.MethodOne();
Console.WriteLine("方法組合A()");
}
public void MethodB() {
s2.MethodOne();
s3.MethodOne();
Console.WriteLine("方法組合B()");
}
}
用戶端調用
由於 Facade的作用,用戶端可以根本不知三個子系統類別的存在。
1
2
3
Facade facade = new Facade();
facade.MethodA();
facade.MethodB();
何時用外觀模式?
「外觀模式」在什麼時候使用最好?
這要分三個階段來說:
- 首先,在設計初期階段,應該要有意識的將不同的兩個層分離,比如經典的三層架構,就需要考慮在資料存取層和業務邏輯層,業務邏輯層和表示層的層與層之間建立外觀
Facade,這樣可以為複雜的子系統提供一個簡單的介面,使得耦合大大降低。 - 其次,在開發階段,子系統往往因為不斷的重構演化而變得越來越複雜,大多數的模式使用時也都會產生很多很小的類別,這原本是好事,但也給外部調用它們的用戶程式帶來了使用上的困難,增加外觀
Facade可以提供一個簡單的介面,減少它們之間的依賴。 - 第三,在維護一個遺留的大型系統時,可以這個系統已經非常難以維護和擴展了,但因為它包含非常重要的功能,新的需求開發必須要依賴於它。此時用外觀模式
Facade也是非常適合的。你可以為新系統開發一個外觀Facade類別,來提供設計粗糙或高度複雜的遺留程式碼的比較清晰簡單的介面,讓新系統與Facade物件互動,Facade與遺留程式碼互動所有複雜的工作。
對於複雜難以維護的老系統,直接去改或去擴展都可能產生很多問題,可以分兩小組:
- 一個開發
Facade與老系統的互動- 另一個只要瞭解
Facade的介面,直接開發新系統調用這些介面即可
可以減少很多不必要的麻煩。
股民炒股程式碼
結構
1
2
3
4
5
6
客戶
股票一
股票二
股票三
公債一
房地產一
程式碼
具體股票、公債、房地產
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
//股票1
class Stock1 {
//賣股票
public void Sell() {
Consloe.WriteLine("股票1 賣出");
}
//買股票
public void Buy() {
Consloe.WriteLine("股票1 買入");
}
}
//股票2
class Stock2 {
//似股票1…略
}
//股票3
class Stock3 {
//似股票1…略
}
//公債1
class NationalDebt1 {
//似股票1…略
}
//房地產1
class Realty1 {
//似股票1…略
}
用戶端調用
用戶需要瞭解股票、公債、房地產情況,需要參與這些項目具體買和賣。耦合性很高。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//用戶端調用
Stock1 s1 = new Stock1();
Stock2 s2 = new Stock2();
Stock3 s3 = new Stock3();
NationalDebt1 nd1 = new NationalDebt1();
Realty1 r1 = new Realty1();
s1.Buy();
s2.Buy();
s3.Buy();
nd1.Buy();
r1.Buy();
s1.Sell();
s2.Sell();
s3.Sell();
nd1.Sell();
r1.Sell();
投資基金程式碼
結構
1
2
3
4
5
6
7
客戶
基金
股票一
股票二
股票三
公債一
房地產一
基金類別
基金類別,它需要瞭解所有的股票或其他投資方式的方法或屬性,進行組合,以備外界調用。
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 Fund {
Stock1 s1;
Stock2 s2;
Stock3 s3;
NationalDebt1 nd1;
Realty1 r1;
public Fund() {
//基金類別,它需要瞭解所有的股票或其他投資方式的方法或屬性,進行組合,以備外界調用
s1 = new Stock1();
s2 = new Stock2();
s3 = new Stock3();
nd1 = new NationalDebt1();
r1 = new Realty1();
}
public void BuyFond() {
s1.Buy();
s2.Buy();
s3.Buy();
nd1.Buy();
r1.Buy();
}
public void SellFund() {
s1.Sell();
s2.Sell();
s3.Sell();
nd1.Sell();
r1.Sell();
}
}
用戶端調用
此時用戶不需要瞭解股票,甚至可以對股票一無所知,買了基金就回家睡覺,一段時間後再贖回就可以大把數錢。
參與股票的操作行為都由基金公司完成。用戶端程式碼非常簡捷明瞭。
1
2
3
Fund fund = new Fund();
fund.BuyFond(); //基金購買
fund.SellFund(); //基金贖回