開發封閉原則(Open-Closed Principle OCP)編程
Software entities(classes,modules,functions etc) should open for extension ,but close for modification.設計模式
什麼意思呢?spa
所謂開放封閉原則就是軟件實體應該對擴展開發,而對修改封閉。開放封閉原則是全部面向對象原則的核心。軟件設計自己所追求的目標就是封裝變化,下降耦合,而開放封閉原則正是對這一目標的最直接體現。設計
開放封閉原則主要體如今兩個方面:code
對擴展開放,意味着有新的需求或變化時,能夠對現有代碼進行擴展,以適應新的狀況。對象
對修改封閉,意味着類一旦設計完成,就能夠獨立其工做,而不要對類盡任何修改。繼承
爲何要用到開放封閉原則呢?接口
軟件需求老是變化的,世界上沒有一個軟件的是不變的,所以對軟件設計人員來講,必須在不須要對原有系統進行修改的狀況下,實現靈活的系統擴展。ip
如何作到對擴展開放,對修改封閉呢?ci
實現開放封閉的核心思想就是對抽象編程,而不對具體編程,由於抽象相對穩定。讓類依賴於固定的抽象,因此對修改就是封閉的;而經過面向對象的繼承和多態機制,能夠實現對抽象體的繼承,經過覆寫其方法來改變固有行爲,實現新的擴展方法,因此對於擴展就是開放的。
對於違反這一原則的類,必須經過重構來進行改善。經常使用於實現的設計模式主要有Template Method模式和Strategy 模式。而封裝變化,是實現這一原則的重要手段,將常常變化的狀態封裝爲一個類。
以銀行業務員爲例
沒有實現OCP的設計:
01 |
public class BankProcess |
02 |
03 |
{ //存款 |
04 |
05 |
public void Deposite(){} |
06 |
07 |
//取款 |
08 |
09 |
public void Withdraw(){ } |
10 |
11 |
//轉帳 |
12 |
13 |
public void Transfer(){} |
14 |
15 |
} |
16 |
17 |
public class BankStaff |
18 |
19 |
{ |
20 |
21 |
private BankProcess bankpro = new BankProcess(); |
22 |
23 |
public void BankHandle(Client client) |
24 |
25 |
{ |
26 |
27 |
switch (client.Type) |
28 |
29 |
{ //存款 |
30 |
31 |
case "deposite" : |
32 |
33 |
bankpro.Deposite(); |
34 |
35 |
break ; |
36 |
37 |
//取款 |
38 |
39 |
case "withdraw" : |
40 |
41 |
bankpro.Withdraw(); |
42 |
43 |
break ; |
44 |
45 |
//轉帳 |
46 |
47 |
case "transfer" : |
48 |
49 |
bankpro.Transfer(); |
50 |
51 |
break ; |
52 |
53 |
} |
54 |
55 |
} |
56 |
57 |
} |
這種設計顯然是存在問題的,目前設計中就只有存款,取款和轉帳三個功能,未來若是業務增長了,好比增長申購基金功能,理財功能等,就必需要修改BankProcess業務類。咱們分析上述設計就不能發現把不能業務封裝在一個類裏面,違反單一職責原則,而有新的需求發生,必須修改現有代碼則違反了開放封閉原則。
從開放封閉的角度來分析,在銀行系統中最可能擴展的就是業務功能的增長或變動。對業務流程應該做爲擴展的部分來實現。當有新的功能時,不須要再對現有業務進行從新梳理,而後再對系統作大的修改。
如何才能實現耦合度和靈活性兼得呢?
那就是抽象,將業務功能抽象爲接口,當業務員依賴於固定的抽象時,對修改就是封閉的,而經過繼承和多態繼承,從抽象體中擴展出新的實現,就是對擴展的開放。
如下是符合OCP的設計:
首先聲明一個業務處理接口
01 |
public interface IBankProcess{ void Process();} |
02 |
03 |
public class DepositProcess : IBankProcess |
04 |
05 |
{ |
06 |
07 |
public void Process() |
08 |
09 |
{ //辦理存款業務 |
10 |
11 |
Console.WriteLine( "Process Deposit" ); |
12 |
13 |
} |
14 |
15 |
} |
16 |
17 |
public class WithDrawProcess : IBankProcess |
18 |
19 |
{ |
20 |
21 |
public void Process() |
22 |
23 |
{ //辦理取款業務 |
24 |
25 |
Console.WriteLine( "Process WithDraw" ); |
26 |
27 |
} |
28 |
29 |
} |
30 |
31 |
public class TransferProcess : IBankProcess |
32 |
33 |
{ |
34 |
35 |
public void Process() |
36 |
37 |
{ //辦理轉帳業務 |
38 |
39 |
Console.WriteLine( "Process Transfer" ); |
40 |
41 |
} |
42 |
43 |
} |
44 |
45 |
public class BankStaff |
46 |
47 |
{ |
48 |
49 |
private IBankProcess bankpro = null ; |
50 |
51 |
public void BankHandle(Client client) |
52 |
53 |
{ |
54 |
55 |
switch (client.Type) |
56 |
57 |
{ //存款 |
58 |
59 |
case "Deposit" : |
60 |
61 |
userProc = new DepositUser(); |
62 |
63 |
break ; |
64 |
65 |
//轉帳 |
66 |
67 |
case "Transfer" : |
68 |
69 |
userProc = new TransferUser(); |
70 |
71 |
break ; |
72 |
73 |
//取款 |
74 |
75 |
case "WithDraw" : |
76 |
77 |
userProc = new WithDrawUser(); |
78 |
79 |
break ; |
80 |
81 |
} |
82 |
83 |
userProc.Process(); |
84 |
85 |
} |
86 |
87 |
} |
這樣當業務變動時,只須要修改對應的業務實現類就能夠,其餘不相干的業務就沒必要修改。當業務增長,只須要增長業務的實現就能夠了。
設計建議:
開放封閉原則,是最爲重要的設計原則,Liskov替換原則和合成/聚合複用原則爲開放封閉原則提供保證。
能夠經過Template Method模式和Strategy模式進行重構,實現對修改封閉,對擴展開放的設計思路。
封裝變化,是實現開放封閉原則的重要手段,對於常常發生變化的狀態,通常將其封裝爲一個抽象,例如銀行業務中IBankProcess接口。
拒絕濫用抽象,只將常常變化的部分進行抽象。