2016年2月14日 星期日

倉儲模式

Repository Pattern (倉儲模式)最主要是定義如何切割 BLL 層跟 DAL 層之間的相依性,讓 BLL 層不用依賴於 DAL 層的實做。並且在有需要更換 DAL 目標的時候,可以有抽換 DAL 層的能力。

相依性的問題

底下類別圖用來描述密碼驗證過程中三個相關連的物件。

public class Validation
    {
        public bool CheckAuthentication(string id, string password)
        {
            // 根據 UI 輸入的 ID 取得資料庫中已加密的密碼
            Account account = new Account();
            string pwd_db = account.GetPassword(id);
            // 將 client 端傳進來的密碼執行加密運算
            Hash hash = new Hash();
            string pwd_ui = hash.Encrypt(password);
            // 比對以上二個步驟的結果
            return pwd_db == pwd_ui;
        }
    }
    public class Account
    {
        internal string GetPassword(string id)
        {
            //連接DB
            throw new NotImplementedException();
        }
    }
    public class Hash
    {
        internal string Encrypt(string password)
        {
            //MD5碼編
            throw new NotImplementedException();
        }
    }

上面這個例子,用戶端要使用時只需這麼叫用:

Validation validation = new Validation();
    string id = "";
    string password = "";
    var result = validation.CheckAuthentication(id, password);

在 CheckAuthentication 方法裡頭,它的邏輯很簡單,取得密碼,取得 Hash 結果,比對二者是否相同。 程式碼本身符合單一職責原則,將不同的職責,交由不同的物件負責,再透過物件之間的互動來滿足使用者需求。 不過在這段程式碼裡頭, CheckAuthentication 方法本身其實根本無須在乎 Account 以及 Hash 物件,因為那不屬於它的商業邏輯。 如果你要執行或測試 CheckAuthentication 方法,就勢必連同 Account 以及 Hash 物件都必須一起完成測試,這帶表它們之間存在著緊密的相依性。

隔離物件之間的相依性

要隔離物件之間的相依性,主要原則就是不要在目標物件中直接初始化相依物件。 也就是不要直接使用 new 建立一個實例,而是將相依物件抽離出來,使用介面來取代。

public interface IAccount
    {
        string GetPassword(string id);
    }
    public interface IHash
    {
        string Encrypt(string id);
    }
    public class ValidationRepository
    {
        public bool CheckAuthentication(string id, string password)
        {
            //取得 user 加密後密碼
            IAccount account = new Account();
            string pwd_db = account.GetPassword(id);
            //將 client 端傳進來的密碼進行 md5 編碼
            IHash hash = new Hash();
            string pwd_ui = hash.Encrypt(password);
            // 比對hash後的密碼,與資料中的密碼是否吻合
            return pwd_db == pwd_ui;
        }
    }
    public class Account : IAccount
    {
        public string GetPassword(string id)
        {
            throw new NotImplementedException();
        }
    }
    public class Hash : IHash
    {
        public string Encrypt(string id)
        {
            throw new NotImplementedException();
        }
    }

上面這個方法,就是就是所謂的「依賴注入」(Dependency Injection), 它將相依性由原本目標物件內,轉移到目標物件之外,所以也稱作「控制反轉」,也就是 IoC (Inversion of Control)。 如此一來,目標物件就可以專注於自身的商業邏輯,而不直接相依於任何實體物件,僅相依於介面。而這也是目標物件的擴充點,或是接縫,提供了未來實作新的物件,來進行擴充或抽換相依物件模組,而不必修改到目標物件的 context 內容。

用 Repository Pattern 抽離對 Entity Framework 的依賴

沒有留言:

張貼留言