面試必會的設計模式:適配器模式

java後端技術漫談 發佈 2020-01-04T04:17:21+00:00

前言《設計模式自習室》系列,顧名思義,本系列文章帶你溫習常見的設計模式。

前言

《設計模式自習室》系列,顧名思義,本系列文章帶你溫習常見的設計模式。主要內容有:

  • 該模式的介紹,包括: 引子、意圖(大白話解釋) 類圖、時序圖(理論規範)
  • 該模式的代碼示例:熟悉該模式的代碼長什麼樣子
  • 該模式的優缺點:模式不是萬金油,不可以濫用模式
  • 該模式的實際使用案例:了解它在哪些重要的源碼中被使用

該系列會逐步更新於我的博客和公眾號(博客見文章底部),也希望各位觀眾老爺能夠關注我的個人公眾號:後端技術漫談,不會錯過精彩好看的文章。

系列文章回顧

  • 【設計模式自習室】開篇:為什麼我們要用設計模式?
  • 【設計模式自習室】建造者模式
  • 【設計模式自習室】原型模式
  • 【設計模式自習室】透徹理解單例模式
  • 【設計模式自習室】理解工廠模式的三種形式

結構型——適配器模式

引子

當你從中國到國外旅遊時,經常會購買一個電源適配器,也就是電源轉接頭,因為國外的插座經常無法適用於國內的插頭,這個電源轉接頭就是一個適配器,也就是下圖中的Adapter,它讓你的插頭能夠正常的在國外使用。

客戶類調用適配器的方法時,在適配器類的內部將調用適配者類的方法,而這個過程對客戶類是透明的,客戶類並不直接訪問適配者類。

定義

適配器模式把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作

適配器模式有類的適配器模式和對象的適配器模式兩種不同的形式。

1. 類適配器

創建新類,繼承源類,同時還要實現新接口

class  adapter extends oldClass implements newFunc{}

2. 對象適配器

創建新類的實例,其中包含舊的類,並實現新接口

class adapter implements newFunc { private oldClass oldInstance ;}

  • 類適配器使用對象繼承的方式,是靜態的定義方式
  • 對象適配器使用對象組合的方式,是動態組合的方式。

類圖

如果看不懂UML類圖,可以先粗略瀏覽下該圖,想深入了解的話,可以繼續谷歌,深入學習:

適配器模式包含如下角色:

  • Target:目標抽象類:這就是所期待得到的新接口類。
  • Adapter:適配器類:適配器類是本模式的核心。適配器把源接口轉換成目標接口。顯然,這一角色不可以是接口,而必須是具體類。
  • Adaptee:適配者類:等待適配的舊類
  • Client:客戶端調用者

1. 類適配器

2. 對象適配器

時序圖

時序圖(Sequence Diagram)是顯示對象之間交互的圖,這些對象是按時間順序排列的。時序圖中顯示的是參與交互的對象及其對象之間消息交互的順序。

我們可以大致瀏覽下時序圖,如果感興趣的小夥伴可以去深究一下:

代碼示例/使用場景舉例

這次我將代碼示例和使用場景兩個章節合起來講,是因為有一個十分典型的Java 源碼可以學習

1. Java容器中的Enumeration老接口和Iterator新接口

JDK1.1 之前提供的容器有Arrays,Vector,Stack,Hashtable,Properties,BitSet,其中定義了一種訪問群集內各元素的標準方式,稱為 Enumeration(列舉器)接口。

JDK1.2 版本中引入了 Iterator接口,新版本的集合對(HashSet,HashMap,WeakHeahMap,ArrayList,TreeSet,TreeMap, LinkedList)是通過 Iterator 接口訪問集合元素。

這樣,如果將老版本的程序運行在新的 Java 編譯器上就會出錯。因為 List 接口中已經沒有 elements(),而只有 iterator() 了。那麼如何將老版本的程序運行在新的 Java 編譯器上呢? 如果不加修改,是肯定不行的,但是修改要遵循「開-閉」原則我們可以用 Java 設計模式中的適配器模式解決這個問題。

public class EnumIter implements Iterator {//重點1:配器實現目標接口

   private Enumeration e;//重點2:適配器持有被適配接口(對象)的引用

   public EnumIter(Enumeration e){
       this.e = e;
   }


   //將對目標對象的調用轉發給真正的被適配的對象
   public boolean hasNext() {
       return e.hasMoreElements();
   }
   public Object next() {
       return e.nextElement();
   }
   public void remove() {

   }
}

NewEnumeration 是一個適配器類,通過它實現了從 Iterator 接口到 Enumeration 接口的適配,這樣我們就可以使用老版本的代碼來使用新的集合對象了。

2. JDBC也是一種適配器模式

Sun公司在1996年公開了Java語言的資料庫連接工具JDBC,JDBC使得Java語言程序能夠與資料庫連接,並使用SQL語言來查詢和操作數據。JDBC給出一個客戶端通用的抽象接口,每一個具體資料庫引擎(如SQL Server、Oracle、MySQL等)的JDBC驅動軟體都是一個介於JDBC接口和資料庫引擎接口之間的適配器軟體。抽象的JDBC接口和各個資料庫引擎API之間都需要相應的適配器軟體,這就是為各個不同資料庫引擎準備的驅動程序。

模式優缺點

優點

  • 將目標類和適配者類解耦,而無須修改原有代碼。
  • 對於客戶端類來說是透明的,而且提高了適配者的復用性。

類適配器模式還具有如下優點:

由於適配器類是適配者類的子類,因此可以在適配器類中置換一些適配者的方法,使得適配器的靈活性更強。

對象適配器模式還具有如下優點:

一個對象適配器可以把多個不同的適配者適配到同一個目標,也就是說,同一個適配器可以把適配者類和它的子類都適配到目標接口。

缺點

過多的使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是A接口,其實內部被適配成了B接口的實現,一個系統如果太多出現這種情況,無異於一場災難。

因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。

總結

建議儘量使用對象適配器的實現方式,多用合成/聚合、少用繼承。當然,具體問題具體分析,根據需要來選用實現方式,最適合的才是最好的。

參考

  • https://www.jianshu.com/p/93821721bf08
  • https://github.com/CyC2018/CS-Notes/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%20-%20%E9%80%82%E9%85%8D%E5%99%A8.md
  • 《HEAD FIRST 設計模式》
  • 《劍指offer》

關注我

我是一名後端開發工程師。

主要關注後端開發,數據安全,爬蟲,物聯網,邊緣計算等方向,歡迎交流。

各大平台都可以找到我

  • 微信公眾號:後端技術漫談
  • Github:@qqxx6661
  • CSDN:@Rude3Knife
  • 知乎:@Zhendong
  • 簡書:@蠻三刀把刀
  • 掘金:@蠻三刀把刀

原創博客主要內容

  • Java面試知識點複習全手冊
  • 設計模式/數據結構 自習室
  • Leetcode/劍指offer 算法題解析
  • SpringBoot/SpringCloud菜鳥入門實戰系列
  • 爬蟲相關技術文章
  • 後端開發相關技術文章
  • 逸聞趣事/好書分享/個人興趣

個人公眾號:後端技術漫談

公眾號:後端技術漫談.jpg

如果文章對你有幫助,不妨收藏,投幣,轉發,在看起來~

關鍵字: