目錄java
與電源適配器類似,在適配器模式中引入了一個被稱爲適配器(Adapter)的包裝類,而它所包裝的對象稱爲適配者(Adaptee),即被適配的類。適配器的實現就是把客戶類的請求轉化爲對適配者的相應接口的調用。也就是說:當客戶類調用適配器的方法時,在適配器類的內部將調用適配者類的方法,而這個過程對客戶類是透明的,客戶類並不直接訪問適配者類。所以,適配器讓那些因爲接口不兼容而不能交互的類能夠一塊兒工做。
適配器模式能夠將一個類的接口和另外一個類的接口匹配起來,而無須修改原來的適配者接口和抽象目標類接口,它是一種使用頻率很是高的設計模式,在軟件開發中得以普遍應用,在Spring等開源框架、驅動程序設計(如JDBC中的數據庫驅動程序)中也使用了適配器模式git
適配器模式(Adapter Pattern):將一個接口轉換成客戶但願的另外一個接口,使接口不兼容的那些類能夠一塊兒工做,其別名爲包裝器(Wrapper)。適配器模式既能夠做爲類結構型模式,也能夠做爲對象結構型模式。數據庫
在適配器模式中,咱們經過增長一個新的適配器類來解決接口不兼容的問題,使得本來沒有任何關係的類能夠協同工做。根據適配器類與適配者類的關係不一樣,適配器模式可分爲對象適配器和類適配器兩種,在對象適配器模式中,適配器與適配者之間是關聯關係;在類適配器模式中,適配器與適配者之間是繼承(或實現)關係。在實際開發中,對象適配器的使用頻率更高,對象適配器模式結構如圖所示:編程
Target設計模式
public interface Home { void watchTv(); void useFridge(); }
Adaptee1app
public class Haier { public void watchHaierTv(){ System.out.println("看海爾電視啦"); } public void userHaierFridge(){ System.out.println("使用海爾冰箱啦"); } }
Adaptee2框架
public class Media { public void watchMediaTv(){ System.out.println("看美的電視啦"); } public void userMediaFridge(){ System.out.println("使用美的冰箱啦"); } }
Adapter編程語言
public class HomeAdapter implements Home{ private Haier haier; private Media media; public HomeAdapter() { this.haier = new Haier(); this.media = new Media(); } @Override public void watchTv() { haier.watchHaierTv(); } @Override public void useFridge() { media.userMediaFridge(); } }
Testide
public class Test { public static void main(String[] args) { //這邊可以使用配置文件經過反射來得到具體的適配器 Home home=new HomeAdapter(); home.watchTv(); home.useFridge(); } } //看海爾電視啦 //使用美的冰箱啦
類適配器模式和對象適配器模式最大的區別在於適配器和適配者之間的關係不一樣,對象適配器模式中適配器和適配者之間是關聯關係,而類適配器模式中適配器和適配者是繼承關係,代碼以下:this
class Adapter extends Adaptee implements Target { public void request() { specificRequest(); } }
因爲Java、C#等語言不支持多重類繼承,所以類適配器的使用受到不少限制,例如若是目標抽象類Target不是接口,而是一個類,就沒法使用類適配器;此外,若是適配者Adapter爲最終(Final)類,也沒法使用類適配器。在Java等面向對象編程語言中,大部分狀況下咱們使用的是對象適配器,類適配器較少使用。
在對象適配器的使用過程當中,若是在適配器中同時包含對目標類和適配者類的引用,適配者能夠經過它調用目標類中的方法,目標類也能夠經過它調用適配者類中的方法,那麼該適配器就是一個雙向適配器,代碼以下:
class Adapter implements Target,Adaptee { //同時維持對抽象目標類和適配者的引用 private Target target; private Adaptee adaptee; public Adapter(Target target) { this.target = target; } public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } public void request() { adaptee.specificRequest(); } public void specificRequest() { target.request(); } }
平時開發不多使用雙向適配器。
當不須要實現一個接口所提供的全部方法時,可先設計一個抽象類實現該接口,併爲接口中每一個方法提供一個默認實現(空方法),那麼該抽象類的子類能夠選擇性地覆蓋父類的某些方法來實現需求,它適用於不想使用一個接口中的全部方法的狀況,又稱爲單接口適配器模式,代碼以下:
抽象類中實現了一些接口方法做爲默認實現
public abstract class AbstractHomeAdapter implements Home{ protected Haier haier=new Haier(); protected Media media=new Media(); @Override //默認看海爾電視 public void watchTv() { haier.watchHaierTv(); } //默認使用美的冰箱 @Override public void useFridge() { media.userMediaFridge(); } }
繼承該抽象類的子類可選擇性的覆蓋一些方法,其餘方法則使用父類的默認實現
public class OtherHomeAdapter extends AbstractHomeAdapter { @Override //重寫方法,其餘方法默認 public void useFridge() { super.haier.userHaierFridge(); } }
對於類適配器來講,其使用具備必定侷限性
(1)對於Java、C#等不支持多重類繼承的語言,一次最多隻能適配一個適配者類,不能同時適配多個適配者(只能繼承一個類,但能夠包含多個類);
(2)適配者類不能爲最終類,如在Java中不能爲final類,C#中不能爲sealed類(最終類了就不能繼承了);
(3)在Java、C#等語言中,類適配器模式中的目標抽象類只能爲接口,不能爲類(由於不能繼承2個類)。
對於對象適配器來講,與類適配器模式相比,要在適配器中置換適配者類的某些方法比較麻煩(修改原有的方法)。
適配器模式將現有接口轉化爲客戶類所指望的接口,實現了對現有類的複用。