![關注公衆號,獲取最新更新](http://static.javashuo.com/static/loading.gif)
沒有將實現變化封裝在抽象和層次結構中時,將致使這種壞味。算法
表現形式一般以下:c#
開閉原則(OCP)指出,類型應對擴展開放,對修改關閉。也就是說應該經過擴展(而不是修改)來改變類型的行爲。沒有在類型或層次結構中封裝實現變化時,便違反了OCP。微信
沒有預測到關注點可能發生變化,進而沒有在設計中正確封裝這些關注點。ide
將彼此獨立的各個關注點聚合在一個層次結構中,而不是分開時,若是關注點發生變化,可能致使類的數量呈爆炸式增加。post
採用過於簡單的方法,如爲每種變化組合建立一個類時,可能致使設計無謂的複雜。學習
假設有一個Entryption類,它須要使用加密算法對數據進行加密。可供選擇的加密算法有不少,包括DES(數據加密標準)、AES(高級加密標準)、TDES(三重數據加密標準)等。Entryption類使用DES算法對數據進行加密。this
public class Encryption { /// <summary> /// 使用DES算法進行加密 /// </summary> public void Encrypt() { // 使用DES算法進行加密 } }
假設出現了新需求,要求使用AES算法對數據進行加密。加密
最差的方案出現了:spa
public class Encryption { /// <summary> /// 使用DES算法進行加密 /// </summary> public void EncryptUsingDES() { // 使用DES算法進行加密 } /// <summary> /// 使用AES算法進行加密 /// </summary> public void EncryptUsingAES() { // 使用AES算法進行加密 } }
這種方案有不少不盡如人意的地方:設計
不滿意就重構,首先使用繼承進行重構,會有2種方案能夠選擇:
選擇1:
讓Encryption類根據需求繼承AESEncryptionAlgorithm或DESEncryptionAlgorithm類,並提供方法Encrypt()。這種方案帶來的問題是Encryption類在編譯階段就將關聯到特定的加密算法,更嚴重的是類之間的關係並非is-a關係。
/// <summary> /// AES算法加密類 /// </summary> public class AESEncryptionAlgorithm { /// <summary> /// 使用AES算法進行加密 /// </summary> public void EncryptUsingAES() { // 使用AES算法進行加密 } } /// <summary> /// DES算法加密類 /// </summary> public class DESEncryptionAlgorithm { /// <summary> /// 使用DES算法進行加密 /// </summary> public void EncryptUsingDES() { // 使用DES算法進行加密 } } public class Encryption: AESEncryptionAlgorithm { /// <summary> /// 使用算法進行加密 /// </summary> public void Encrypt() { EncryptUsingAES(); } }
選擇2:
建立子類AESEncryption和DESEncryption,它們都擴展了Encryption類,並分別包含加密算法AES和DES的實現。客戶程序可建立Encryption的引用,這些引用指向特定子類的對象。經過添加新的子類,很容易支持新的加密算法。可是這種方案的問題是AESEncryption和DESEncryption將繼承Encryption類的其它方法,下降了加密算法的可重用性。
public abstract class Encryption { /// <summary> /// 使用算法進行加密 /// </summary> public abstract void Encrypt(); } /// <summary> /// AES算法加密類 /// </summary> public class AESEncryption : Encryption { /// <summary> /// 使用 AES算法進行加密 /// </summary> public override void Encrypt() { // 使用 AES算法進行加密 } } /// <summary> /// DES算法加密類 /// </summary> public class DESEncryption : Encryption { /// <summary> /// 使用 DES算法進行加密 /// </summary> public override void Encrypt() { // 使用 DES算法進行加密 } }
最佳的選擇是使用策略模式:
/// <summary> /// 算法加密接口 /// </summary> public interface EncryptionAlgorithm { void Encrypt(); } /// <summary> /// DES算法加密類 /// </summary> public class DESEncryptionAlgorithm : EncryptionAlgorithm { public void Encrypt() { //使用 DES算法進行加密 } } /// <summary> /// AES算法加密類 /// </summary> public class AESEncryptionAlgorithm : EncryptionAlgorithm { public void Encrypt() { //使用 AES算法進行加密 } } public class Encryption { private EncryptionAlgorithm algo; public Encryption(EncryptionAlgorithm algo) { this.algo = algo; } /// <summary> /// 使用算法進行加密 /// </summary> public void Encrypt() { algo.Encrypt(); } }
支持使用不一樣算法(DES和AES)對各類內容(Image和Text)進行加密的設計。
最簡單最直觀的的設計:
在這個設計中,有兩個變化點:支持的內容類型和加密算法類型。對於這兩個變化點的每種可能組合,都使用了一個類來表示。這樣會有一個嚴重的問題:假設如今要求支持新加密算法TDES和新內容類型Data,類的數量呈爆炸性增加。由於變化點混在了一塊兒,沒有分別進行封裝。
使用橋接模式進行封裝:
使用橋接模式,分別封裝這兩個關注點的變化。如今要引入新內容類型Data和新加密算法TDES,只須要添加兩個新類。既解決了類數量呈爆炸增加的問題,又增長了根爲接口EncryptionAlgorithm層次結構中的加密算法的可重用性。
不相關的關注點混在一塊兒,抽象將變得難以重用。
對業務中可能的變化點,要給予擴展點,保證開閉原則(OCP),對擴展開放,對修改關閉。
參考:《軟件設計重構》