什麼是接口(中級篇)——接口在設計模式中的使用(二)

還記得個人軟件工程老師是這麼說的:軟件應該往高內聚,低耦合的方向進行設計。html

當時,還身爲一個初學者的我,不太明白老師的這句話——既然面向對象提供給了咱們」繼承「這種高耦合的概念,那爲什麼咱們還要低耦合高內聚呢?難道放着繼承的概念不用,而改成面向過程嗎?數據庫

帶着這一疑問,我請教了個人老師,他給個人回答是:經過接口來分隔分離邏輯,就能夠達到低耦合的效果。架構

 

咱們來回顧一下前一篇所學習的"控制反轉"設計思想,其實質就是上面所說的"經過接口來分離邏輯"。函數

 

但以上一篇的示例來講,達到這個目標,還有一些欠缺,首先讓咱們來回顧一下上一篇的代碼內容學習

/// <summary>
/// 這是一個負責登陸的接口類型
/// </summary>
public interface ILoginChecker
{
    /// <summary>
    /// 登陸,須要的參數是用戶名和密碼,須要返回一個bool類型表示登陸是否成功
    /// </summary>
    /// <param name="loginName"></param>
    /// <param name="password"></param>
    /// <returns></returns>
    bool Login(string loginName, string password);
}

public class LoginWindow : Form
{
    private ILoginChecker loginChecker;
    
    /// <summary>
    /// 經過構造函數決定使用哪一個ILoginChecker來負責登陸流程
    /// </summary>
    /// <param name="chcker"></param>
    public LoginWindow(ILoginChecker chcker)
    {
        this.loginChecker = chcker;
    }

    void LoginButton_Click(object sender, EventArgs e)
    {
        string loginName = null, password = null;
        //從控件上取值
        //判斷空值
        //等一切OK時
        if (this.loginChecker.Login(loginName, password))
        {
            //登陸成功
        }
        else
        {
            //登陸失敗
        }
    }
}

 

確定會有一些人帶着這樣的疑問:在代碼的某個地方必定寫着類型這樣的內容:this

///實例化某個實現了ILoginChecker接口的類型
ILoginChecker checker = new XXXLoginChecker();
LoginWindow window = new LoginWindow(checker);
window.Show();

那麼隨着之後功能的更新,在不斷地修改這裏的ILoginChecker checker = new XXXLoginChecker();spa

時間久了,記不得這段代碼寫在哪兒,也是很頭疼的一件事,最重要的是,依然沒達到」易維護「的效果,和以前相同,每次的須求改更,或是環境變化,都須要重寫這句話。設計

若是能有一個容器,可以在運行時(注1)判斷使用哪一個ILoginChecker類型,那就方便多了。code

 

運行時:與"編譯時"相對應,好比我說定義一個變量Int32 i,這個i的類型就是Int32,這是在編譯時決定的,由於程序在由代碼編譯爲程序時,已經能夠肯定i就是一個Int32類型了。orm

再好比說我定義一個變量Object obj,這個obj的類型雖然是Object,可是會根據實際的賦值,發生類型的變換,而賦的什麼值給它,程序在編譯時是沒法得知的,只有在運行到這裏的時候才能知道,這就叫運行時。

 

咱們來假設一個現實場景:

場景中,咱們把ILoginChecker這個接口

一、門衛是由保安公司派出的

二、保安公司根據每一個需求方的要求不一樣,配備不一樣的保安

三、保安公司擁有知足各類需求的保安

 

這樣一來,咱們就要再補充一個至關因而保安公司的類型了,用來建立ILoginChecker實例

因此咱們起個名字叫LoginCheckerFactory

裏面只有一個主要方法:CreateLoginChecker,根據咱們指定的名稱,返回一個具體的IloginChecker實例,咱們來看一下示例代碼:

class LoginCheckerFactory
{
    public ILoginChecker CreateLoginChecker(string checkerName)
    {
        switch (checkerName)
        {
            case "Database": return new DatabaseLoginChecker(); //由數據庫完成的登陸驗證
            case "WebService": return new WebServiceLoginChecker(); //由WebService完成的登陸驗證
            case " TCP": return new TCPLoginChecker(); //由TCP通信完成的登陸驗證
            default: throw new ApplicationException("不存在這個名稱的Checker實例");
        }
    }
}

 

此時,你會發現,登陸的斷定流程是依賴於一個字符串,Database或WebService或TCP。到了這一步,我想大部分人都明白,這個字符串只要寫在配置文件裏,就大功告成了。

而後項目發佈,在不一樣的運行環境中間,我只須要改一下配置文件,就能實現各類方式的登陸了。

 

對於更新與維護是一樣的便捷,你能夠把不一樣版本的ILoginChecker都放在這個工廠裏,而後根據外部的一些版本號來更改實例。

在BUG的修正中,你也沒必要直接修改類型自己,能夠拷備一個出來,好比叫WebServiceLoginChecker2,這樣即保證了程序原有的可運行性,又能夠進行BUG的修正,一旦出現了」動一發觸全身「的狀況,也很是容易全身而退。

 

這樣的設計思想、模式,咱們將其稱之爲工廠模式。工廠模式還分爲簡單工廠模式和抽象工廠模式,可是其最核心的思想,就是建立一個工廠,由工廠在運行時,進行動態的實例建立、返回。大大降底的類與類、模塊與模塊之間的耦合度,爲更新與維護提供了很是好的隔離環境。

 

小結

經過第1、第二篇文章的學習,一種初步的構架思路已經產生。

一、分析當前方法要的主要事情

二、將可能存在變動的邏輯,創建接口,待之後實現

三、考慮到上述接口的實現多樣性,創建工廠類型,由工廠類型負責建立接口實例

 

利與弊的權衡

從作產品的角度考慮,一個好的基本構架是產品最核心的保障,有了這樣的保障,能夠說,除非到你換語種的那一天,不然永遠不會存在(推倒重來)的那一天,由於你的每個環節都被低耦合了,它們所有均可以被單獨替換。

從作項目的角度考慮,一個好的基本構架是項目中最耗時間、最耗成本的階段。在面向結果的項目負責人眼中,相對於可維護性進度纔是最重要的,因此在作項目這種狀況下,對使用架構應該進行一個速與質的權衡。

 

文章爲做者原創,轉載請標明出處,謝謝  http://www.cnblogs.com/ShimizuShiori/p/4929300.html

相關文章
相關標籤/搜索