
没有将实现变化封装在抽象和层次结构中时,将致使这种坏味。算法
表现形式一般以下: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),对扩展开放,对修改关闭。
参考:《软件设计重构》