1. 程式人生 > >設計模式(三)——介面卡設計模式

設計模式(三)——介面卡設計模式

今天覆習這樣一種設計模式,當客戶端想要使用一個類,但是這個類的介面並不符合客戶端的要求時,我們就會想到這個設計模式——介面卡設計模式,把一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起工作的兩個類能夠在一起工作
介面卡模式分為兩種:類的介面卡模式和物件的介面卡模式。
首先,這兩種模式的類圖關係分別為:
1.類的介面卡模式
2.物件的介面卡模式

然後,來個例項理解理解,反正這個設計模式,我理解的時候也是想了挺長時間的,希望大家好好把握“協同”工作的意義。
1.類的介面卡模式

目標介面:

package com.xdccl.zwj.AdapterDesignPatterns.ClassAdapterDesignPattern;
//目標角色:類介面卡設計模式中,這裡只能是一個介面
public interface Target {
	public void get110v() ;
	public void get220v() ;
}

源角色:
package com.xdccl.zwj.AdapterDesignPatterns.ClassAdapterDesignPattern;
//源角色,只具有特定的方法,如果Target介面改變,這個類是不能被修改的
//同時,這個類的介面和標準介面不同,需要這個類和實現標準介面的類協同操作(理解這裡的協同的意思)
public class Adaptee {
	public void get220v(){
		System.out.println("源角色----220v");
	}
}

介面卡:
package com.xdccl.zwj.AdapterDesignPatterns.ClassAdapterDesignPattern;
//介面卡:對源角色進行擴充套件,實現了目標角色,從而使得目標角色改動時候,不用改動源角色,只要改動介面卡即可 
public class Adapter extends Adaptee implements Target {

	@Override
	public void get110v() {
		System.out.println("介面卡---110v");
	}

}

客戶端:
package com.xdccl.zwj.AdapterDesignPatterns.ClassAdapterDesignPattern;

public class Client {
	public static void main(String args[]){
		//面向客戶端的只有Target介面
		Target target = new Adapter() ;			//在需求中,這裡的程式碼是不可以改變的
		target.get110v() ;				//這裡使用的是介面卡中的方法
		target.get220v() ;			//這裡使用的源角色的方法
		//從程式碼中可以看出,都是使用target物件,卻可以使用源角色和介面卡中的方法,這裡就體現了協同的作用
	}
	
}

如上程式碼所示,正確的輸出應該是這樣的:

介面卡---110v
源角色----220v

2.物件的介面卡模式

這裡的目標介面和源角色的程式碼可以不變,需要對介面卡和客戶端程式碼進行修改:

介面卡:

package com.xdccl.zwj.AdapterDesignPatterns.ObjectAdapterDesignPattern.copy;
//這裡和類介面卡不同的就是,需要拿到Adaptee的引用,這樣,相當於是一個代理的作用了
public class Adapter implements Target {
	private Adaptee adaptee ;
	public Adapter(Adaptee adaptee){		//建構函式
		this.adaptee = adaptee ;
	}
	@Override
	public void get110v() {
		System.out.println("介面卡---110v");
	}

	@Override
	public void get220v() {
		adaptee.get220v() ;
	}

}

客戶端:

package com.xdccl.zwj.AdapterDesignPatterns.ObjectAdapterDesignPattern.copy;

public class Client {
	public static void main(String args[]){
		//面向客戶端的只有Target介面
		Adaptee adaptee = new Adaptee() ;				//這裡需要將源物件作為引數傳到介面卡中
		Target target = new Adapter(adaptee) ;			//物件介面卡的好處就是這裡的Target可以是一個類
		target.get110v() ;				//這裡使用的是介面卡中的方法
		target.get220v() ;			//這裡使用的源角色的方法
		//從程式碼中可以看出,都是使用target物件,卻可以使用源角色和介面卡中的方法,這裡就體現了協同的作用
	}
	
}

結果和類介面卡模式的示例結果完全一樣。 最後,在網上找了點這兩種介面卡模式的對比,貼上來大家自己看看吧
(1)類介面卡使用物件繼承的方式,是靜態的定義方式;而物件介面卡使用物件組合的方式,是動態組合的方式。
(2)對於類介面卡,由於介面卡直接繼承了Adaptee,使得介面卡不能和Adaptee的子類一起工作,因為繼承是靜態的關係,當介面卡繼承了Adaptee後,就不可能再去處理  Adaptee的子類了。
(3)對於物件介面卡,一個介面卡可以把多種不同的源適配到同一個目標。換言之,同一個介面卡可以把源類和它的子類都適配到目標介面。因為物件介面卡採用的是物件組合的關係,只要物件型別正確,是不是子類都無所謂。
(4)對於類介面卡,介面卡可以重定義Adaptee的部分行為,相當於子類覆蓋父類的部分實現方法。
(5)對於物件介面卡,要重定義Adaptee的行為比較困難,這種情況下,需要定義Adaptee的子類來實現重定義,然後讓介面卡組合子類。雖然重定義Adaptee的行為比較困難,但是想要增加一些新的行為則方便的很,而且新增加的行為可同時適用於所有的源。
(6)對於類介面卡,僅僅引入了一個物件,並不需要額外的引用來間接得到Adaptee。
(7)對於物件介面卡,需要額外的引用來間接得到Adaptee。

(8)建議儘量使用物件介面卡的實現方式,多用合成/聚合、少用繼承。當然,具體問題具體分析,根據需要來選用實現方式,最適合的才是最好的。

看完了這些給大家丟擲一個小問題,如果目標介面不是一個介面,而變成了目標類,那麼程式碼應該做什麼改變呢?完成這個小問題來檢驗下有沒有很好的理解這個設計模式吧。