將一個類的接口裝換成客戶但願的另一個接口。適配器模式使得原來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。android
適配器模式由三部分組成:bash
- Target(目標抽象類):目標抽象類定義客戶所需接口,能夠是一個抽象類或接口,也能夠是具體類。
- Adapter(適配器類):適配器能夠調用另外一個接口,做爲一個轉換器,對Adaptee和Target進行適配,適配器類是適配器模式的核心。
- Adaptee(適配者類):適配者即被適配的角色,它定義了一個已經存在的接口,這個接口須要適配,適配者類通常是一個具體類,包含了客戶但願使用的業務方法。
2.2.1 Android(Target抽象類)框架
public interface Android {
void isAndroid();
}
複製代碼
2.2.2 Iphone(Adaptee類)iphone
public class Iphone {
public void isIphone() {
System.out.println("這是一個適配蘋果充電線的接口");
}
}
複製代碼
2.2.3 Adapter類ide
/**
* 將安卓手機的接口轉化爲蘋果手機可用的充電接口
*/
public class Adapter extends Iphone implements Android {
@Override
public void isAndroid() {
isIphone();
}
}
複製代碼
2.2.4 客戶端調用學習
public class Client {
public static void main(String[] args) {
Android android = new Adapter();
android.isAndroid();
}
}
複製代碼
2.3.1 優勢this
- 因爲適配器類是適配者的子類,所以能夠在適配器類中置換一些適配者的方法,使得適配器的靈活性更強。
2.3.1 缺點spa
- 對於Java、C#等不支持多重類繼承的語言,一次最多隻能適配一個適配者類,不能同時適配多個適配者。
- 適配者類不能爲最終類,如在Java中不能爲final類,C#中不能爲sealed類。
- 在Java、C#等語言中,類適配器模式中的目標抽象類只能爲藉口,不能爲類,其使用有必定的侷限性。
角色與類適配器模式同樣3d
3.2.1 Android(Target抽象類)code
public interface Android {
void isAndroid();
}
複製代碼
3.2.2 Iphone(Adaptee類)
public class Iphone {
public void isIphone() {
System.out.println("這是一個適配蘋果充電線的接口");
}
}
複製代碼
3.2.3 Adapter類
/**
* 將安卓手機的接口轉化爲蘋果手機可用的充電接口
*/
public class Adapter implements Android {
private Iphone iphone;
public Adapter(Iphone iphone) {
this.iphone = iphone;
}
@Override
public void isAndroid() {
iphone.isIphone();
}
}
複製代碼
3.2.4 客戶端調用
public class Client {
public static void main(String[] args) {
Android android = new Adapter(new Iphone());
android.isAndroid();
}
}
複製代碼
3.3.1 優勢
- 一個對象適配器能夠把多個不一樣的適配者適配到同一個目標。
- 能夠適配一個適配者的子類,因爲適配器和適配者之間是關聯關係,根據「里氏替換原則」,適配者的子類也可經過該適配器進行適配。
3.3.2 缺點
- 與類適配器模式相比,要在適配器中置換適配者類的某些方法比較麻煩。若是必定要置換掉適配者類的一個或多個方法,能夠先作一個適配者類的子類,將適配者類的方法置換掉,而後再把適配者類的子類當作真正的適配者進行適配,實現過程較爲複雜。
缺省適配器由兩部分組成:
- Target(目標角色):目標接口。能夠定義有不少方法,但這些方法不必定全都被用戶類所須要。
- Default Adapter(缺省適配器):缺省適配模式的核心。它實現Target角色接口,爲因此方法提供空的實現。
4.2.1 Target
public interface SubjectTarget {
void learnChinese();
void learnEnglish();
void learnMath();
void learnBiological();
}
複製代碼
4.2.2 Default Adapter
public abstract class SubjectAdapter implements SubjectTarget {
@Override
public void learnChinese() {
}
@Override
public void learnEnglish() {
}
@Override
public void learnMath() {
}
@Override
public void learnBiological() {
}
}
複製代碼
4.2.3 客戶端調用
public class Client {
public static void main(String[] args) {
SubjectAdapter subjectAdapter = new SubjectAdapter() {
@Override
public void learnEnglish() {
System.out.println("學習英語使我快樂");
}
};
subjectAdapter.learnEnglish();
}
}
複製代碼
- 系統須要複用現有類,而該類的接口不符合系統的需求,可使用適配器模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。
- 想建立一個能夠重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在未來引進的類一塊兒工做。
- 靈活使用時:選擇對象適配器。類適配器使用對象繼承的方式,是靜態的定義方式;而對象適配器使用對象組合的方式,是動態組合的方式。
- 須要同時配置源類和其子類:選擇對象適配器。對於類適配器,因爲適配器直接繼承了Adaptee,使得適配器不能和Adaptee的子類一塊兒工做,由於繼承是靜態的關係,當適配器繼承了Adaptee後,就不可能再去處理Adaptee的子類;對於對象適配器,一個適配器能夠把多種不一樣的源適配到同一個目標。換言之,同一個適配器能夠把源類和它的子類都適配到目標接口。由於對象適配器採用的是對象組合的關係,只要對象類型正確,是否是子類都無所謂。
- 須要從新定義Adaptee的部分行爲:選擇類適配器。對於類適配器,適配器能夠重定義Adaptee的部分行爲,至關於子類覆蓋父類的部分實現方法。對於對象適配器,要重定義Adaptee的行爲比較困難,這種狀況下,須要定義Adaptee的子類來實現重定義,而後讓適配器組合子類。雖然重定義Adaptee的行爲比較困難,可是想要增長一些新的行爲則方便的很,並且新增長的行爲可同時適用全部的源。
- 僅僅但願使用方便時:選擇類適配器。對於類適配器,僅僅引入了一個對象,並不須要額外的引用來間接獲得Adaptee。對於對象適配器,須要額外的引用來間接獲得Adaptee。
- 將目標類和適配者類解耦,經過引入一個適配器類來重用現有的適配者類,而無須修改原有代碼。
- 增長了類的透明性和複用性,將具體的實現封裝在適配者類中,對於客戶端類來講是透明的,並且提升了適配者的複用性。
- 靈活性和擴展性都很是好,經過使用配置文件,能夠很方便地更換適配器,也能夠在不修改原有代碼的基礎上增長新的適配器類,徹底符合「開閉原則」。
- 過多地使用適配器,會讓系統很是零亂,不易總體進行把握。好比,明明看到調用的是A接口,其實內部被適配成了B接口的實現,一個系統若是出現太多這種狀況,無異於一場災難。所以若是不是頗有必要,能夠不適用適配器,而是直接對系統進行重構。
- 對於類適配器而言,因爲Java至多繼承一個類,因此至多隻能適配一個適配者類,並且目標類必須是抽象類。
特別聲明:一、如若文中有錯之處,歡迎大神指出。 二、文章是參考網上一些大神的文章,本身整理出來的,如如有侵權,可聯繫我刪除。