適配器模式最好在詳細設計階段不要考慮它,它不是爲了解決還處於開發階段的問題,而是解決正在服役的項目問題,沒有一個系統分析師會在作詳細設計的時候考慮使用適配器模式,這個模式使用的主要場景是擴展應用中。html
注意:項目必定要遵照依賴倒置原則和里氏替換原則,不然即便在適合使用適配器的場合下,也會帶來很是大的改造。java
程序設計的原則可參考:程序設計原則設計模式
1.定義:適配器模式(Adapter Pattern)是做爲兩個不兼容的接口之間的橋樑。這種類型的設計模式屬於結構型模式,它結合了兩個獨立接口的功能。ide
2.適配器模式分類:類適配器、對象適配器、接口適配器測試
3.意圖:將一個類的接口轉換成客戶但願的另一個接口。適配器模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。this
4.主要解決:主要解決在軟件系統中,經常要將一些"現存的對象"放到新的環境中,而新環境要求的接口是現對象不能知足的。spa
5.優勢: 一、可讓任何兩個沒有關聯的類一塊兒運行。 二、提升了類的複用。 三、增長了類的透明度。 四、靈活性好。設計
6.缺點: 一、過多地使用適配器,會讓系統很是零亂,不易總體進行把握。好比,明明看到調用的是 A 接口,其實內部被適配成了 B 接口的實現,一個系統若是太多出現這種狀況,無異於一場災難。所以若是不是頗有必要,能夠不使用適配器,而是直接對系統進行重構。 2.因爲 JAVA 至多繼承一個類,因此至多隻能適配一個適配者類,並且目標類必須是抽象類。htm
原理:經過繼承來實現適配器功能。中間件
當咱們要訪問的接口A中沒有咱們想要的方法 ,卻在另外一個接口B中發現了合適的方法,咱們又不能改變訪問接口A,在這種狀況下,咱們能夠定義一個適配器p來進行中轉,這個適配器p要實現咱們訪問的接口A,這樣咱們就能繼續訪問當前接口A中的方法(雖然它目前不是咱們的菜),而後再繼承接口B的實現類BB,這樣咱們能夠在適配器P中訪問接口B的方法了,這時咱們在適配器P中的接口A方法中直接引用BB中的合適方法,這樣就完成了一個簡單的類適配器。
下面使用員工的信息爲例:
需求更改前,員工信息的接口:
public interface IStaff { String getName(); int getAge(); }
需求更改前,員工信息的實現:
public class Staff implements IStaff { private String name; private int age; @Override public String getName() { return name; } @Override public int getAge() { return age; } }
需求更改後,新增員工合同時間信息的接口:
public interface IContract { int getContractTime(); }
需求更改後,新增員工合同時間信息的實現:
public class Contract implements IContract { private int contractTime; @Override public int getContractTime() { return contractTime; } }
需求更改後,新增合同員工信息的實現:
public class ContractStaff extends Contract implements IStaff { private String name; private int age; @Override public String getName() { return name; } @Override public int getAge() { return age; } }
測試代碼:
public static void main(String args[]) { /*** 須要更改前,員工信息獲取 ***/ IStaff staff = new Staff(); staff.getName(); staff.getAge(); /*** 須要更改後,新增的合同員工的信息獲取 ***/ IStaff contractStaff = new ContractStaff(); contractStaff.getName(); contractStaff.getAge(); /*** 新增信息:獲取合同員工合同時間 ***/ ((ContractStaff) contractStaff).getContractTime(); }
原理:經過組合來實現適配器功能。
當咱們要訪問的接口A中沒有咱們想要的方法 ,卻在另外一個接口B中發現了合適的方法,咱們又不能改變訪問接口A,在這種狀況下,咱們能夠定義一個適配器p來進行中轉,這個適配器p要實現咱們訪問的接口A,這樣咱們就能繼續訪問當前接口A中的方法(雖然它目前不是咱們的菜),而後在適配器P中定義私有變量C(對象)(B接口指向變量名),再定義一個帶參數的構造器用來爲對象C賦值,再在A接口的方法實現中使用對象C調用其來源於B接口的方法。
舉個例子:220v機器須要適配110v電壓
110v電壓接口:
public interface IV110 { int output(); }
110v電壓實現:
public class V110 implements IV110 { @Override public int output() { return 110; } }
220v電壓接口:
public interface IV220 { int output(); }
220v電壓實現:
public class V220 implements IV220 { @Override public int output() { return 220; } }
220v機器的接口:
public interface IMachine220V { boolean is220V(); }
220v機器的實現:
public class Machine220V implements IMachine220V { private int v; public Machine220V(int v){ this.v = v; } @Override public boolean is220V() { return v == 220; } }
110v轉220v適配器:
public class Adapter implements IV220{ private IV110 iv110; public Adapter(IV110 iv110) { this.iv110 = iv110; } @Override public int output() { return iv110.output() * 2; } }
測試:
public static void main(String args[]){ /*** 正常狀況下:220v機器使用220v電壓 ***/ V220 v220 = new V220(); Machine220V machine1 = new Machine220V(v220.output()); System.out.println("machine1 : " + machine1.is220V()); /*** 電壓不一樣的狀況下:220v機器使用110v電壓 ***/ V110 v110 = new V110(); Adapter adapter = new Adapter(v110); Machine220V machine2 = new Machine220V(adapter.output()); System.out.println("machine2 : " + machine2.is220V()); }
輸出:
machine1 : true
machine2 : true
原理:經過抽象類來實現適配,這種適配稍別於上面所述的適配。
當存在這樣一個接口,其中定義了N多的方法,而咱們如今卻只想使用其中的一個到幾個方法,若是咱們直接實現接口,那麼咱們要對全部的方法進行實現,哪怕咱們僅僅是對不須要的方法進行置空(只寫一對大括號,不作具體方法實現)也會致使這個類變得臃腫,調用也不方便,這時咱們可使用一個抽象類做爲中間件,即適配器,用這個抽象類實現接口,而在抽象類中全部的方法都進行置空,那麼咱們在建立抽象類的繼承類,並且重寫咱們須要使用的那幾個方法便可。
目標接口:
public interface IWorkMethod { void method_1(); void method_2(); void method_3(); void method_4(); void method_5(); }
適配器:
public abstract class WorkMethodAdapter implements IWorkMethod { public void method_1(){} public void method_2(){} public void method_3(){} public void method_4(){} public void method_5(){} }
實現類:
public class AWorkMethodAdapter extends WorkMethodAdapter { public void method_1(){ System.out.println("work with method1"); } public void method_2(){ System.out.println("work with method2"); } }
測試:
public static void main(String args[]){ AWorkMethodAdapter aWorkMethod = new AWorkMethodAdapter(); aWorkMethod.method_1(); aWorkMethod.method_2(); }
類適配器與對象適配器的使用場景一致,僅僅是實現手段稍有區別,兩者主要用於以下場景:
(1)想要使用一個已經存在的類,可是它卻不符合現有的接口規範,致使沒法直接去訪問,這時建立一個適配器就能間接去訪問這個類中的方法。
(2)咱們有一個類,想將其設計爲可重用的類(可被多處訪問),咱們能夠建立適配器來將這個類來適配其餘沒有提供合適接口的類。
以上兩個場景其實就是從兩個角度來描述一類問題,那就是要訪問的方法不在合適的接口裏,一個從接口出發(被訪問),一個從訪問出發(主動訪問)。
接口適配器使用場景:
(1)想要使用接口中的某個或某些方法,可是接口中有太多方法,咱們要使用時必須實現接口並實現其中的全部方法,可使用抽象類來實現接口,並不對方法進行實現(僅置空),而後咱們再繼承這個抽象類來經過重寫想用的方法的方式來實現。這個抽象類就是適配器。