設計模式系列之「介面卡模式」

YoungManSter發表於2017-11-30

**小C:**小Y,家裡的插孔沒有兩孔的怎麼辦?
**小Y:**so easy,淘寶電源轉換插頭包郵只要九塊九毛九,真的只要九塊九毛九。
......
**小C:**iPhone x變成Lightning接頭,傳統的耳機會不會用不了?
**小Y:**又沒有這麼牛叉的機,你問這個幹啥呢(小Y有點不好的預感啊)?買個轉換線唄。
**小C:**哦,沒事就問問。

後來呢,小Y幾個月只能吃泡麵了過日子了,嗚嗚嗚......

其實大家也要學學小Y這種為博紅顏一笑,勒緊褲頭吃泡麵的無謂精神(一定要看好自己的信用卡啊)。言歸正傳,現實生活中有各種各樣的介面卡,方便至極,那麼,介面卡這樣的工作,在我們的程式裡有嗎?答案是必須的,介面卡模式。

文章內容思維導圖

一、基本概念

1.定義

將一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起工作的兩個類能夠在一起工作。即定義一個包裝類,用於包裝不相容介面的物件。

2.應用場景
  • 有動機修改一個已經上線的介面時並且不符合你的需求,介面卡模式可能是最適合你的模式。
3.角色介紹

通用UML.png

  • Target目標角色

    該角色定義把其他類轉換為何種介面,也就是我們的期望介面。

  • Adaptee源角色

    需要轉換成目標角色的源角色,它是已經存在的、執行良好的類或物件,經過介面卡角色的包裝,它會成為一個嶄新的角色。

  • Adapter介面卡角色

    介面卡模式的核心角色,其他兩個角色都是已經存在的角色,而介面卡角色是需要新建立的,它的職責非常簡單:把源角色通過繼承或者類關聯的方法轉換為目標角色。

二、程式碼的實現

好了,該是讓這次的主角iPhone差的轉換線出場了(無限心傷中.....)

設計模式系列之「介面卡模式」

在這之前還需要知道介面卡模式的形式分為:類的介面卡模式物件的介面卡模式

1.兩種不同形式適配模式的UML對比

設計模式系列之「介面卡模式」

兩者的差別就是一個是通過繼承,一個是通過組合,利用例項的方式去進行

2.兩種不同形式適配模式的程式碼實現

(1)兩者實現程式碼的相同部分

①iPhone X手機介面(Target介面)

public interface PhoneInterface {  
	/**  
	 * Lightning耳機介面
 	*/  
	void lightningHeadSet();  
}  
複製程式碼

②Lightning介面耳機

public class LightningHeadSet implements PhoneInterface {  
	@Override  
	public void lightningHeadSet() {  
    	System.out.print("使用Lightning介面的耳機連線。");  
	}  
}  
複製程式碼

③傳統耳機介面(源類Adaptee)

public interface TraditionPhoneInterface {   
	/**  
	 * 傳統耳機介面  
	 */  
	void traditionHeadSet();  
}  
複製程式碼

④傳統介面耳機

public class TraditionHeadSet implements TraditionPhoneInterface{  

	@Override  
	public void traditionHeadSet() {  
    	System.out.print("使用傳統介面的耳機連線。");  
	}  
}  
複製程式碼

(2)類的介面卡模式的實現

建立介面卡類(繼承傳統耳機(源類)和實現Linghtning介面(Target))

public class HeadSetAdapter extends TraditionHeadSet implements PhoneInterface{  
	@Override  
	public void lightningHeadSet() {  
    	super.traditionHeadSet();  
	}  
}  
複製程式碼

為什麼會去繼承TraditionHeadSet和實現PhoneInterface呢?是因為使用者最終是需要用到Lightning介面去實現聽歌,所以要呼叫lightningHeadSet(),但是介面卡的作用就是讓傳統耳機實現Lightning的轉化,最終用傳統耳機都能夠得到連線。

(3)物件的介面卡模式的實現(推薦)

public class ObjectHeadSetAdapter implements PhoneInterface {  

	private TraditionPhoneInterface traditionHeadSet;  

	public ObjectHeadSetAdapter(TraditionPhoneInterface traditionHeadSet) {  
    	this.traditionHeadSet=traditionHeadSet;  
	}  

	@Override  
	public void lightningHeadSet() {  
    	traditionHeadSet.traditionHeadSet();  
	}  
}  
複製程式碼

為什麼只實現PhoneInterface介面的理由同上。

(4)客戶端輸出

public class Client {
	public static void main(String[] args){
    	//直接通過lightning介面連線
    	LightningHeadSet lightningHeadSet=new LightningHeadSet();
    	lightningHeadSet.lightningHeadSet();
    	//通過類的介面卡進行連線
    	HeadSetAdapter headSetAdapter=new HeadSetAdapter();
    	headSetAdapter.lightningHeadSet();
    	//通過物件的介面卡進行連線
    	TraditionPhoneInterface traditionSet=new TraditionHeadSet();
    	ObjectHeadSetAdapter objectHeadSetAdapter=new ObjectHeadSetAdapter(traditionSet);
    	objectHeadSetAdapter.lightningHeadSet();
	}
}
複製程式碼

輸出的結果為:

①使用Lightning介面的耳機連線。  
②使用傳統介面的耳機連線。  
③使用傳統介面的耳機連線。  
複製程式碼

3.物件的介面卡 vs 類的介面卡

  • 類的介面卡中Adapter與Adaptee是繼承關係,因為java是不支援多繼承的,因此不適合出現多個源類;物件的介面卡模式不是使用繼承關係連線到Adaptee類,而是使用委派關係連線到Adaptee類,這種關聯的方法可以動態組合多個源類。
  • 類的介面卡是繼承被適配類,所以相對靜態;而物件的介面卡包含被適配類,所以相對靈活。
  • 類的介面卡通過 Override 來擴充套件新需求;而物件的介面卡因為包含關係所以不能擴充套件。

三、優缺點

1.類的介面卡的優缺點

(1)優點

  • 使用方便,程式碼簡化,不需要引入物件例項。

(2)缺點

  • 高耦合,靈活性低。使用物件繼承的方式,是靜態的定義方式。

2.物件的介面卡的優缺點

(1)優點

  • 靈活性高、低耦合 ,採用 “物件組合”的方式,是動態組合方式。

(2)缺點

  • 使用複雜,需要引入物件例項。

3.介面卡的優缺點

(1)優點

  • 提高了類的複用度。源角色在原有的系統中可以正常使用,在目標角色中又可以充當新的角色。
  • 增加了類的透明性,客戶端可以呼叫同一介面,因而對客戶端來說是透明的。
  • 靈活性好。增加刪除不影響原有程式碼。
  • 符合開閉原則。

(2)缺點

  • 過多的使用介面卡,會讓系統非常零亂,不易整體進行把握。

四、總結

在選用介面卡模式的時候根據需要來選用合適的實現方式,儘量使用物件的介面卡模式,多用動態組合合、少用繼承。

Android技術交流吧

相關文章