C#接口顯示實如今實際開發中的做用

摘要

任何一個C#入門的程序員都知道——當一個類型在實現接口的時候,有兩種方法實現:顯式實現、隱式實現。並且你們也都知道,當一個類型實現的兩個接口存在相同成員定義時,顯示實現能夠解決這種狀況。html

 

可是,在一個命名比較規範的項目中,幾乎不可能出現上述狀況。程序員

 

那麼,顯示實現有什麼具體存在的意義嗎?數據庫

本人根據這小几年的開發歷經,感受顯式實現最覺的兩個做用就是:框架

  1. 改變接口成員的使用權限
  2. 改變接口成員的出入參數

下面本人將會對這兩種做用進一一說明函數


接口定義

本篇文章將會使用一個示例來說述這兩個做用。this

咱們先來看一下示例吧:spa

  1. 定義一個接口類型,表示一個"元件",元件擁有兩個成員
    1. 元件名稱,主要是用來和其它元件進行區分
    2. 使用元件,須要一個Object類型的參數,表示將元件使用在哪一個目標對象上
  2. 定義一個接口類型,表示一個"元件工廠",用來生成"元件"的實例,元件工廠擁有兩個成員
    1. 根據指定的元件名稱,生成一個元件實例
    2. 註冊一個元件,只有被註冊過的元件纔可以被生產

 

例子仍是挺簡單的,咱們來把這些接口類型碼出來吧:code

/// <summary>
/// 一個元件接口
/// </summary>
interface IComponent
{
    /// <summary>
    /// 元件的名稱,用於區別於其它元件
    /// </summary>
    String ComponentName { get; }

    /// <summary>
    /// 使用這個元件
    /// <param name="target">對哪一個對象使用這個元件</param>
    /// </summary>
    void Use(Object target);
}

/// <summary>
/// 一個元件工廠接口
/// </summary>
interface IComponentFactory
{
    /// <summary>
    /// 建立元件
    /// </summary>
    /// <param name="componentName"></param>
    /// <returns></returns>
    IComponent CreateComponent(String componentName);

    /// <summary>
    /// 註冊一個元件
    /// </summary>
    /// <param name="component"></param>
    void RegistComponent(IComponent component);
}

 


 

 

實現鎖與鑰匙的關係

光有接口,咱們是沒法工做的。所以咱們開發一個叫鑰匙的元件,再開發一個密碼鎖,鑰匙能夠用來開密碼鎖,當二者的編號相同時,鎖才能夠被打開。咱們再作一個工廠,根據鎖的編號生成一把鑰匙,而後就能夠開鎖了。component

咱們先用隱式實現來作這件事htm

/// <summary>
/// 密碼鎖
/// </summary>
class PasswordLocker
{
    /// <summary>
    /// 開鎖用的密碼
    /// </summary>
    public String Code { get; set; }
}

/// <summary>
/// 鑰匙
/// </summary>
class Key : IComponent
{
    /// <summary>
    /// 對應的解鎖密碼,只有和鎖的Code相同時才能夠開鎖
    /// </summary>
    public string Code { get; set; }

    public string ComponentName
    {
        get { return this.Code; }
    }

    public void Use(object target)
    {
        //因爲入參是繼承了接口的Object類型,因此必須先對入參進行類型判斷
        if (target is PasswordLocker)
        {
            PasswordLocker pl = (PasswordLocker)target;
            if (pl.Code == this.Code) Console.WriteLine("打開鎖了");
            else Console.WriteLine("未能把鎖打開");
        }
        else
            Console.WriteLine("目前類型不是鎖,暫時不能使用該元件");

    }
}

/// <summary>
/// 鑰匙工廠
/// </summary>
class KeyFactory : IComponentFactory
{
    private Dictionary<String, IComponent> components = new Dictionary<string, IComponent>();

    public IComponent CreateComponent(string componentName)
    {
        return components[componentName];
    }

    /// <summary>
    /// 由外部建立一個元件
    /// </summary>
    /// <param name="component"></param>
    public void RegistComponent(IComponent component)
    {
        components[component.ComponentName] = component;
    }
}

而後咱們再寫一代段碼使用他們:

PasswordLocker locker = new PasswordLocker();
locker.Code = "12345";

Key k = new Key();
k.Code = "12345";
KeyFactory factory = new KeyFactory();
factory.RegistComponent(k);
factory.CreateComponent(locker.Code).Use(locker);

功能所有OK,可是有一些小小的瑕疵:

  1. 這把鑰匙從代碼上看,還能夠用在不是PasswordLocker的類型上,因此Use方法中還要對入參類型進行判斷;
  2. 明明是鑰匙工廠,但從代碼上看生產出來的依然只是元件接口類型,註冊的時候也是,希可以直接使用鑰匙類型;
  3. 若是個人元件工廠是可以自動在實例化的時候,從數據庫裏註冊好全部元件了,那我天然不但願調用工廠的人能夠繼續Regist元件。

確實如此,當一個項目大到多人合做的時候,可以有着明確的入參與返回類型私有化不須要其它人員調用的成員,是頗有必要的一件事。

因此如今回頭看剛纔的那段實現代碼,咱們能夠提出如下要求:

  1. 鑰匙只能對鎖進行Use
  2. 工廠從數據庫中初始化全部鑰匙,而後再也不開放Regist方法
  3. 工廠生成出來的元件就是鑰匙,而不是其它類型。

 

對新要求的實現:

咱們經過對接口的顯示實現,以保證接口成員不能夠被顯示的調用。再定義須要的public方法,調用接口成員,以達到上面三個要求:

/// <summary>
/// 這是一個僅僅能用於開密碼鎖的元件,使用了現式實現改變入參
/// </summary>
class PasswordLockerKey : IComponent
{
    private string code;

    public PasswordLockerKey(String code)
    {
        this.code = code;
    }

    string IComponent.ComponentName
    {
        get { return this.code; }
    }

    void IComponent.Use(object target)
    {
        PasswordLocker pl = (PasswordLocker)target;
        if (pl.Code == this.code) Console.WriteLine("打開鎖了");
        else Console.WriteLine("未能把鎖打開");
    }

    /// <summary>
    /// 利用顯示繼承,隱藏了以Object做爲入參的方法,並開放了一個僅僅以PasswordLocker做爲入參的方法。改變了參數類型
    /// </summary>
    /// <param name="locker"></param>
    public void User(PasswordLocker locker)
    {
        //將自身轉化爲接口類型,再調用Use纔可使用顯式實現的方法
        ((IComponent)this).Use(locker);
    }
}

/// <summary>
/// 基於數據庫的鑰匙工廠,使用顯式實現改變了接口成員的訪問權限
/// </summary>
class DataBaseKeyFactory : IComponentFactory
{
    private Dictionary<String, PasswordLockerKey> keys = new Dictionary<string, PasswordLockerKey>();

    /// <summary>
    /// 在構造函數的同時,從數據庫中加載出全部鑰匙
    /// </summary>
    public DataBaseKeyFactory()
    {
        IComponentFactory f = (IComponentFactory)this;
        foreach (PasswordLockerKey k in LoadKeyFromDatabase())
        {
            f.RegistComponent(k);
        }
    }

    /// <summary>
    /// 這是模擬的經過數據庫加載鑰匙的方法
    /// </summary>
    /// <returns></returns>
    protected virtual IEnumerable<PasswordLockerKey> LoadKeyFromDatabase()
    {
        return new List<PasswordLockerKey>() 
        { 
            new PasswordLockerKey("12345")
        };
    }

    IComponent IComponentFactory.CreateComponent(string componentName)
    {
        return keys[componentName];
    }

    void IComponentFactory.RegistComponent(IComponent component)
    {
        keys[component.ComponentName] = (PasswordLockerKey)component;
    }

    /// <summary>
    /// 這裏改變了本來接口的返回類型
    /// </summary>
    /// <param name="code"></param>
    /// <returns></returns>
    public PasswordLockerKey CreateComponent(string code)
    {
        return (PasswordLockerKey)((IComponentFactory)this).CreateComponent(code);
    }
}

代碼中模擬了一下從數據庫中取數的過程。

經過上面的方法,咱們最終在使用這些類形的時候會發現,Use的入參對象只能是PasswordLocker,Factory不能夠Regist成員了,Create時必定是PasswordLockerKey類型。已經基本知足上面的須要了。

 


小結

在實際項目中,其實這些現象依然是不多見的。每每出如今底層接口框架被搭建好後,對接口類型進行一次基礎實現時,可能會遇到這些問題。

本人寫此文章,但願你們在遇到相似問題的時候,可以想到可使用接口的顯示實現來解決。

但願可以你們帶來一些提示和幫助。

 

 

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

相關文章
相關標籤/搜索