利斯科夫替代原則

為什麼要使用 LSP

場景: 假設我們有 3 個資料庫(抵押客戶,經常賬戶客戶和儲蓄賬戶客戶)提供客戶資料,我們需要客戶的姓氏客戶詳細資訊。現在,根據給定的姓氏,我們可以從這 3 個資料庫中獲得超過 1 個客戶詳細資訊。

履行

商業模式層:

public class Customer
{
    // customer detail properties...
}

資料訪問層:

public interface IDataAccess
{
    Customer GetDetails(string lastName);
}

上面的介面由抽象類實現

public abstract class BaseDataAccess : IDataAccess
{
    /// <summary> Enterprise library data block Database object. </summary>
    public Database Database;    
    public Customer GetDetails(string lastName)
    {
        // use the database object to call the stored procedure to retirve the customer detials
    }
}

這個抽象類為所有 3 個資料庫都有一個通用方法 GetDetails,它由每個資料庫類擴充套件,如下所示

抵押客戶資料訪問:

public class MortgageCustomerDataAccess : BaseDataAccess
{
    public MortgageCustomerDataAccess(IDatabaseFactory factory)
    {
        this.Database = factory.GetMortgageCustomerDatabase();
    }
}

當前賬戶客戶資料訪問:

public class CurrentAccountCustomerDataAccess : BaseDataAccess
{
    public CurrentAccountCustomerDataAccess(IDatabaseFactory factory)
    {
        this.Database = factory.GetCurrentAccountCustomerDatabase();
    }
}

節省賬戶客戶資料訪問:

public class SavingsAccountCustomerDataAccess : BaseDataAccess
{
    public SavingsAccountCustomerDataAccess(IDatabaseFactory factory)
    {
        this.Database = factory.GetSavingsAccountCustomerDatabase();
    }
}

一旦設定了這 3 個資料訪問類,現在我們將注意力吸引到客戶端。在 Business 層中,我們有 CustomerServiceManager 類,它將客戶 detials 返回給客戶端。

業務層:

public class CustomerServiceManager : ICustomerServiceManager, BaseServiceManager
{
   public IEnumerable<Customer> GetCustomerDetails(string lastName)
   {
        IEnumerable<IDataAccess> dataAccess = new List<IDataAccess>()
        {
            new MortgageCustomerDataAccess(new DatabaseFactory()), 
            new CurrentAccountCustomerDataAccess(new DatabaseFactory()),
            new SavingsAccountCustomerDataAccess(new DatabaseFactory())
        };

        IList<Customer> customers = new List<Customer>();

       foreach (IDataAccess nextDataAccess in dataAccess)
       {
            Customer customerDetail = nextDataAccess.GetDetails(lastName);
            customers.Add(customerDetail);
       }

        return customers;
   }
}

我沒有展示依賴注入以保持簡單,因為它現在已經變得複雜了。

現在,如果我們有一個新的客戶詳細資料庫,我們可以新增一個擴充套件 BaseDataAccess 並提供其資料庫物件的新類。

當然,我們在所有參與的資料庫中需要相同的儲存過程

最後,CustomerServiceManagerclass 的客戶端將只呼叫 GetCustomerDetails 方法,傳遞 lastName,而不應關心資料的來源和位置。

希望這能為你提供一種理解 LSP 的實用方法。