C#設計模式學習筆記:(6)適配器模式

来源:https://www.cnblogs.com/atomy/archive/2020/01/18/12200978.html
-Advertisement-
Play Games

本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7640873.html,記錄一下學習過程以備後續查用。 一、引言 從今天開始我們開始講結構型設計模式,結構型設計模式有如下幾種:適配器模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式。 創建型設 ...


    本筆記摘抄自: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類型,針對微軟SQL Server類型的資料庫在和DataSet之間進行適配。

    五、總結

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

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

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這兩天看opencv-python的HSV色彩空間,在寫程式時發現用HSV來提取圖像區域是件令人噁心的麻煩事。拿閾值分割做個對比,閾值最多也就一兩個參數需要調整;但是HSV需要對三個通道調整上下限,也就是起碼有6個參數。於是乎,就一時興起決定做個小程式,把參數都做成滑動塊,這樣自然方便許多。一開始, ...
  • 一、什麼式方法區 方法區,也稱非堆(Non Heap),又是一個被線程共用的記憶體區域。其中主要存儲載入的類位元組碼、class/method/field等元數據對象、static final常量、static變數、jit編譯器編譯後的代碼等數據。另外,方法區包含了一個特殊的區域“運行時常量池”。 (1 ...
  • JVM體繫結構圖 Native Interface(本地介面) Java本地介面(Java Native Interface (JNI))允許運行在Java虛擬機(Java Virtual Machine (JVM))上的代碼調用本地程式和類庫,或者被它們調用,這些程式和類庫可以是其它語言編寫的,比 ...
  • 準備年後要跳槽,所以最近一直再看面試題,並且把收集到的面試題整理了以下發到博客上,希望對大家有所幫助。 首先是集合類的面試題 1. HashMap 排序題,上機題。 已知一個 HashMap<Integer,User>集合, User 有 name(String)和 age(int)屬性。請寫一個方 ...
  • 發現問題 在一次偶然中,在爬取某個網站時,老方法,打開調試工具查看請求方式,請求攔截,是否是非同步載入,不亦樂乎,當我以為這個網站非常簡單的時候,發現二級網頁的地址和源碼不對應 Ajax非同步載入?源碼也是這樣的 而且這些鏈接直... ...
  • 常用的軟體: 播放器: cloundMusic(網易雲音樂) https://music.163.com/#/download PotPlayer(一款強大的視頻播放器) https://daumpotplayer.com/download/ ACDsee(ACDsee圖片編輯器免費版) https ...
  • 想要實現二維數組中根據某個欄位排序,一般可以通過數組迴圈對比的方式實現。這裡介紹一種更簡單的方法,直接通過PHP函數實現。array_multisort() :可以用來一次對多個數組進行排序,或者根據某一維或多維對多維數組進行排序。詳細介紹可參考PHP手冊:https://www.php.net/m ...
  • C 中 ConfigureAwait 相關答疑FAQ 在前段時間經常看到園子里有一些文章討論到 ConfigureAwait,剛好今天在微軟官方博客看到了 "Stephen Toub" 前不久的一篇答疑 ConfigureAwait 的一篇文章,想翻譯過來。 原文地址:https://devblog ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...