1. 程式人生 > WINDOWS開發 >C#設計模式學習筆記:(6)介面卡模式

C#設計模式學習筆記:(6)介面卡模式

本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7640873.html,記錄一下學習過程以備後續查用。

一、引言

從今天開始我們開始講結構型設計模式,結構型設計模式有如下幾種:介面卡模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式。

建型設計模式解決的是物件建立的問題,而結構型設計模式解決的是類和物件組合關係的問題。

今天我們開始講結構型設計模式裡面的第一個設計模式:介面卡模式。介面卡模式其實很簡單,在現實生活中有很多這樣的例項例項:比如,手機充電器的

接頭是二插的,假如只有三插的插座,就必須通過三插轉二插的轉換器才可以正常充電;膝上型電腦的工作電壓和家庭照明的電壓是不一致的,需要通過變壓

器(俗稱火牛)才能讓膝上型電腦正常工作。介面卡的例子數不勝數,只需記住一點:適配就是轉換,讓不能在一起工作的兩樣東西通過轉換可以正常工作。

二、介面卡模式介紹

介面卡模式:英文名稱--Adapter Pattern;分類--結構型。

2.1、動機(Motivate)

在軟體系統中,由於應用環境的變化,常常需要將“一些現存的物件”放在新的環境中應用,但是新的環境要求的介面是這些現存物件所不能滿足的。如何應

對這種“遷移的變化”?如何既能利用現有物件的良好實現,同時又能滿足新的應用環境所要求的介面?

2.2、意圖(Intent)

將一個類的介面轉換成客戶希望的另一個介面。Adapter模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。--《設計模式》Gof

2.3、結構圖(Structure)

介面卡有兩種結構:

1)物件介面卡(更常用)

技術分享圖片

物件介面卡使用的是物件組合的方案,它的Adapter和Adaptee的關係是組合關係。

OO中優先使用組合模式,組合模式不適用時再考慮繼承,因為組合模式更加鬆耦合。而繼承是緊耦合的,父類的任何改動都要導致子類的改動。

2)類介面卡

技術分享圖片

2.4、模式的組成

從上兩圖可以看出,在介面卡模式的結構圖有以下角色:

1)目標角色(Target):定義Client使用的與特定領域相關的介面。


2)客戶角色(Client):與符合Target介面的物件協同。

3)被適配角色(Adaptee):定義一個已經存在並已經使用的介面,這個介面需要適配。

4)介面卡角色(Adapter) :介面卡模式的核心,它將對被適配Adaptee角色已有的介面轉換為目標角色Target匹配的介面並進行適配。

2.5 、介面卡模式的具體實現

2.5.1物件介面卡模式的實現

技術分享圖片技術分享圖片
    class Program
    {
        /// <summary>
        /// 目標角色(Target)--兩孔插座,這裡可以寫成抽象類或者介面。
        /// </summary>
        public class TwoHoleTarget
        {
            //客戶端需要的方法
            public virtual void Request()
            {
                Console.WriteLine("我需要兩孔的插座。");
            }
        }

        /// <summary>
        /// 源角色(Adaptee)--三孔插座,需要適配的類。
        /// </summary>
        public class ThreeHoleAdaptee
        {
            public void SpecificRequest()
            {
                Console.WriteLine("增加三孔轉兩孔的插座,兩孔充電器也可以使用了。");
            }
        }

        /// <summary>
        /// 介面卡類
        /// </summary>
        public class ThreeToTwoAdapter : TwoHoleTarget
        {
            //建立三孔插座的例項
            private ThreeHoleAdaptee threeHoleAdaptee = new ThreeHoleAdaptee();

            /// <summary>
            /// 實現兩孔插座介面方法
            /// </summary>
            public override void Request()
            {
                //具體的轉換工作
                threeHoleAdaptee.SpecificRequest();
            }
        }

        static void Main(string[] args)
        {
            #region 介面卡模式之物件介面卡
            TwoHoleTarget twoHole = new ThreeToTwoAdapter();
            twoHole.Request();
            Console.ReadLine();
            #endregion
        }
    }
View Code

執行結果如下:

技術分享圖片

2.5.2類介面卡模式實現

技術分享圖片技術分享圖片
    class Program
    {
        /// <summary>
        /// 目標角色(Target)--兩孔插座,這裡只能是介面,也是類介面卡的限制。
        /// </summary>
        public interface ITarget
        {
            void Request();
        }

        /// <summary>
        /// 源角色(Adaptee)--三孔插座,需要適配的類。
        /// </summary>
        public abstract class Adaptee
        {
            public void SpecificRequest()
            {
                Console.WriteLine("增加三孔轉兩孔的插座,兩孔充電器也可以使用了。");
            }
        }

        /// <summary>
        /// 介面卡類,介面要放在類的後面,在此無法適配更多的物件,這是類介面卡的不足。
        /// </summary>
        public class Adapter : Adaptee,ITarget
        {
            /// <summary>
            /// 實現兩孔插座介面方法
            /// </summary>
            public void Request()
            {
                //具體的轉換工作
                SpecificRequest();
            }
        }

        static void Main(string[] args)
        {
            #region 介面卡模式之類介面卡
            ITarget twoHole = new Adapter();
            twoHole.Request();
            Console.ReadLine();
            #endregion
        }
    }
View Code

執行結果如下:

技術分享圖片

三、介面卡模式的實現要點

1)Adapter模式主要應用於“希望複用一些現存的類,但是介面又與複用環境要求不一致的情況”,在遺留程式碼複用、類庫遷移等方面非常有用。

2)GoF23定義了兩種Adapter模式的實現結構:物件介面卡和類介面卡。類介面卡採用“多繼承”的實現方式,在C#語言中,如果被適配角色是類,Target的

實現只能是介面,因為C#語言只支援介面的多繼承。在C#語言中類介面卡也很難支援適配多個物件的情況,同時也會帶來了不良的高耦合和違反類的單一職

責的原則,所以一般不推薦使用。物件介面卡採用“物件組合”的方式,更符合鬆耦合精神,對適配的物件也沒限制,可以一個也可以多個,但是,這也使得重

定義Adaptee的行為比較困難,這就需要生成Adaptee的子類並且使得Adapter引用這個子類而不是引用Adaptee本身。Adapter模式可以實現的非常靈活,不必

拘泥於GoF23中定義的兩種結構。例如,完全可以將Adapter模式中的“現存物件”作為新的介面方法引數,來達到適配的目的。

3)Adapter模式本身要求我們儘可能地使用“面向介面的程式設計”風格,這樣才能在後期很方便地適配。

下面詳細總結下介面卡兩種形式的優缺點:

3.1、物件介面卡模式

優點:

1)可以在不修改原有程式碼的基礎上來複用現有類,很好地符合 “開閉原則”。

2)採用 “物件組合”的方式,更符合鬆耦合。

缺點:

1)使得重定義Adaptee的行為較困難,這就需要生成Adaptee的子類並且使得Adapter引用這個子類而不是引用Adaptee本身。

3.2、類介面卡模式

優點:

1)可以在不修改原有程式碼的基礎上來複用現有類,很好地符合 “開閉原則”。

2)可以重新定義Adaptee(被適配的類)的部分行為,因為在類介面卡模式中,Adapter是Adaptee的子類。

3)僅僅引入一個物件,並不需要額外的欄位來引用Adaptee例項(這個即是優點也是缺點)。

缺點:

1)用一個具體的Adapter類對Adaptee和Target進行匹配,當如果想要匹配一個類以及所有它的子類時,類的介面卡模式就不能勝任了。因為類的介面卡模

式中沒有引入Adaptee的例項,光呼叫SpecificRequest方法並不能去呼叫它對應子類的SpecificRequest方法。

2)採用了 “多繼承”的實現方式,帶來了不良的高耦合。

3.3、介面卡模式的使用場景

1)系統需要複用現有類,而該類的介面不符合系統的需求。

2)想要建立一個可重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。

3)對於物件介面卡模式,在設計裡需要改變多個已有子類的介面,如果使用類的介面卡模式,就要針對每一個子類做一個介面卡,而這不太實際。

四、.NET中介面卡模式的實現

說到介面卡模式在.Net中的實現就很多了,比如:System.IO裡面的很多類都有介面卡的影子,當我們操作檔案的時候,其實裡面呼叫了COM的介面實現。

以下兩點也是介面卡使用的案例:

4.1、.NET中複用COM物件

COM物件不符合.NET物件的介面,使用tlbimp.exe來建立一個Runtime Callable Wrapper(RCW)以使其符合.NET物件的介面,COM Interop就好像是

COM和.NET之間的一座橋樑。

4.2、.NET資料訪問類(Adapter變體)

各種資料庫並沒有提供DataSet介面,使用DbDataAdapter可以將任何資料庫訪問/存取適配到一個DataSet物件上,DbDataAdapter在資料庫和DataSet之間

做了很好的適配。當然還有SqlDataAdapter型別,針對微軟SqlServer型別的資料庫在和DataSet之間進行適配。

五、總結

有一句話還是要說的,雖然以前說過。每種設計模式都有自己的適用場景,它是為了解決一類問題,沒有所謂的缺點,沒有一種設計模式可以解決所有情況

的。我們使用設計模式的態度是通過不斷地重構來使用模式,不要一上來就使用設計模式,為了模式而模式。如果軟體沒有需求的變化,我們不使用模式都沒

有問題。遇到問題,我們就按著常規來寫,有了需求變化,然後我們去抽象,瞭解使用的場景,然後再選擇合適的設計模式。