【封裝那些事】 缺失封裝

mark

缺失封裝

沒有將實現變化封裝在抽象和層次結構中時,將致使這種壞味。算法

表現形式一般以下: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算法進行加密
    }
}

這種方案有不少不盡如人意的地方:設計

  • Encryption類變得更大、更難以維護,由於它實現了多種加密算法,可是每次只使用一種。
  • 難以添加新算法以及修改既有算法,由於加密算法是Encryption類不可分割的部分。
  • 加密算法向Encryption類提供服務,可是與Encryption類牢牢耦合在一塊兒,沒法在其它地方重用。

不滿意就重構,首先使用繼承進行重構,會有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算法進行加密
    }
}

最佳的選擇是使用策略模式:

  • 可在運行階段給Encryption對象配置特定的加密算法
  • 可在其它地方重用層次結構EncryptionAlgorithm中定義的算法
  • 很容易根據須要支持新的算法
/// <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)進行加密的設計。

最簡單最直觀的的設計:

mark

在這個設計中,有兩個變化點:支持的內容類型和加密算法類型。對於這兩個變化點的每種可能組合,都使用了一個類來表示。這樣會有一個嚴重的問題:假設如今要求支持新加密算法TDES和新內容類型Data,類的數量呈爆炸性增加。由於變化點混在了一塊兒,沒有分別進行封裝。

mark

使用橋接模式進行封裝:

mark

使用橋接模式,分別封裝這兩個關注點的變化。如今要引入新內容類型Data和新加密算法TDES,只須要添加兩個新類。既解決了類數量呈爆炸增加的問題,又增長了根爲接口EncryptionAlgorithm層次結構中的加密算法的可重用性。

總結

  1. 不相關的關注點混在一塊兒,抽象將變得難以重用。

  2. 對業務中可能的變化點,要給予擴展點,保證開閉原則(OCP),對擴展開放,對修改關閉。

參考:《軟件設計重構》



做者: 擼碼那些事

來源:http://songwenjie.cnblogs.com/
聲明:本文爲博主學習感悟總結,水平有限,若是不當,歡迎指正。若是您認爲還不錯,不妨點擊一下下方的 推薦按鈕,謝謝支持。轉載與引用請註明出處。

微信公衆號:
相關文章
相關標籤/搜索