6.java設計模式之適配器模式
基本需求:
- 將一個220V的電壓輸出成5V的電壓,其中220V電壓為被適配者,變壓器為適配器,5v電壓為適配目標
基本介紹:
- 適配器模式屬於結構型模式,將某個類的介面轉換成客戶端期望的另一個介面表示,主的目的是兼容性,讓原本因介面不匹配不能一起工作的兩個類可以協同工作。其別名為包裝器(Wrapper) 分為類適配器模式,對象適配器模式,介面適配器模式
- 用戶的角度看不到被適配者,是解耦的,用戶調用適配器轉化出來的目標介面方法,適配器再調用被適配者的相關介面方法
類適配器模式:
-
Adapter 類,通過繼承 src 類,實現 dst 類介面,完成 src->dst 的適配
-
UML類圖
-
-
程式碼實現
-
public class Voltage220V { // 被適配類 public int output220V() { System.out.println("輸出220V電壓"); return 220; } } public interface Voltage5V { // 用戶需要使用的介面 int output5V(); } public class VoltageAdapter extends Voltage220V implements Voltage5V { // 適配方法(通過實現用戶使用的介面將配適配的類轉換成用戶所需要的) @Override public int output5V() { int output = output220V() / 44; System.out.println("適配出5V電壓"); return output; } } public class Phone { // 使用介面 public void charging(Voltage5V voltage5V) { voltage5V.output5V(); } } // client調用 public static void main(String[] args) { Phone phone = new Phone(); // 用戶只關心介面 不需要關心被適配者 phone.charging(new VoltageAdapter()); }
-
-
注意事項
- Java是單繼承機制,所以類適配器需要繼承src類這一點算是一個缺點, 因為這要求dst必須是介面,有一定局限性
- src類的方法在Adapter中都會暴露出來,也增加了使用的成本
- 由於其繼承了src類,所以它可以根據需求重寫src類的方法,使得Adapter的靈活性增強了
對象適配器模式:
-
基本思路和類的適配器模式相同,只是將Adapter類作修改,不是繼承src類,而是持有src類的實例,以解決兼容性的問題。即:持有src類,實現dst類介面,完成 src->dst的適配,將被適配者類的對象聚合組合到適配器類中
-
根據「 合成復用原則」,在系統中盡量使用 關聯關係(聚合)來替代繼承關係
-
UML類圖
-
程式碼實現
-
// 只需要對類適配器模式中的適配器類進行修改即可 public class VoltageAdapter implements Voltage5V { // 直接將被適配類對象聚合到適配器中,免去了繼承 // 根據「 合成復用原則」,在系統中盡量使用 關聯關係(聚合)來替代繼承關係 private Voltage220V voltage220V; public VoltageAdapter(Voltage220V voltage220V) { this.voltage220V = voltage220V; } // 適配方法 @Override public int output5V() { int output = voltage220V.output220V() / 44; System.out.println("適配出5V電壓"); return output; } }
-
-
注意事項
- 對象適配器和類適配器其實算是同一種思想,只不過實現方式不同。根據合成復用原則,使用組合替代繼承,所以它解決了類適配器必須繼承src的局限性問題,也不再要求 dst必須是介面
- 使用成本更低,更靈活
介面適配器模式:
-
核心思路:當不需要全部實現介面提供的方法時,可先設計一個抽象類實現介面,並為該介面中每個方法提供一個默認實現(空方法),那麼該抽象類的子類可有選擇地覆蓋父類的某些方法來實現需求
-
適用於一個介面不想使用其所有的方法的情況
-
UML類圖
-
程式碼實現
-
public class Voltage220V { // 被適配類 public int output220V() { System.out.println("輸出220V電壓"); return 220; } } public interface OutputVoltage { // 該介面提供多種方法,適配器抽象類對該介面的全部方法進行空實現 // 使用時用戶只重寫他們關心的那個方法即可,不需要關心其他的方法 int output5V(); int output10V(); int output220V(); } public abstract class VoltageAdapter implements OutputVoltage { // 聚合被適配類 protected Voltage220V voltage220V; public VoltageAdapter(Voltage220V voltage220V) { this.voltage220V = voltage220V; } // 對介面中的所有適配方法進行空實現 @Override public int output5V() { return 0; } @Override public int output10V() { return 0; } @Override public int output220V() { return 0; } } public class Client { public static void main(String[] args) { VoltageAdapter voltageAdapter = new VoltageAdapter(new Voltage220V()) { // 使用時用戶只重寫他們關心的那個方法即可,不需要關心其他的方法 @Override public int output5V() { int i = super.voltage220V.output220V() / 44; System.out.println("適配出5V電壓"); return i; } }; voltageAdapter.output5V(); } }
-
springmvc源碼:
-
springMVC中DispatchServlet中的doDispatch方法 就用到了適配器模式,通過Handler對象適配出了HandlerAdapter對象,通過HandlerAdapter執行Handler對象中的方法
-
DispatcherServlet -> HandlerMapping(得到處理器鏈) -> HandlerAdapter(處理器適配器) -> Handler(處理器) -> ViewAndResolver(視圖解析器) -> 模板等返回給瀏覽器
-
簡單實現DispatcherServlet中的適配器
-
UML類圖
-
程式碼實現
-
// 處理器適配器介面及實現類 public interface MyHandlerAdapter { // 處理器適配器 判斷是那種適配器 boolean support(Object object); // 通過適配器執行處理器中的方法 void handler(Object object); } class MyHttpRequestHandlerAdapter implements MyHandlerAdapter{ @Override public boolean support(Object object) { return object instanceof MyHttpRequestHandler; } @Override public void handler(Object object) { MyHttpRequestHandler myHttpRequestHandler = (MyHttpRequestHandler) object; myHttpRequestHandler.doHttpRequest(); } } class MySimpleControllerHandlerAdapter implements MyHandlerAdapter{ @Override public boolean support(Object object) { return object instanceof MySimpleControllerHandler; } @Override public void handler(Object object) { MySimpleControllerHandler mySimpleControllerHandler = (MySimpleControllerHandler) object; mySimpleControllerHandler.doSimpleController(); } } class MySimpleServletHandlerAdapter implements MyHandlerAdapter{ @Override public boolean support(Object object) { return object instanceof MySimpleServletHandlerAdapter; } @Override public void handler(Object object) { MySimpleServletHandler mySimpleServletHandler = (MySimpleServletHandler) object; mySimpleServletHandler.doSimpleServlet(); } }
-
// 處理器介面及實現類 public interface MyHandler { // 處理器介面 } class MyHttpRequestHandler implements MyHandler { public void doHttpRequest() { System.out.println("doHttpRequest..."); } } class MySimpleControllerHandler implements MyHandler { public void doSimpleController() { System.out.println("doSimpleController..."); } } class MySimpleServletHandler implements MyHandler { public void doSimpleServlet() { System.out.println("doSimpleServlet..."); } }
-
public class MyDispatcherServlet { // 進行spring mvc中DispatcherServlet的簡單實現 private static List<MyHandlerAdapter> myHandlerAdapters = new ArrayList<>(); public MyDispatcherServlet() { myHandlerAdapters.add(new MyHttpRequestHandlerAdapter()); myHandlerAdapters.add(new MySimpleControllerHandlerAdapter()); myHandlerAdapters.add(new MySimpleServletHandlerAdapter()); } public void doDispatcher(String request) { // 實際執行流程 DispatcherServlet -> HandlerMapping(得到處理器鏈) -> HandlerAdapter(處理器適配器) -> Handler(處理器) -> ViewAndResolver(視圖解析器) -> 模板等返回 // 實際 通過HttpServletRequest對象獲取的Handler對象 此處簡化即可 MyHttpRequestHandler myHttpRequestHandler = new MyHttpRequestHandler(); MyHandlerAdapter handlerAdapter = getHandlerAdapter(myHttpRequestHandler); // 通過獲取到的HandlerAdapter對象來執行指定種類Handler的方法 // 不同的HandlerAdapter執行Handler的方法的方式不一樣 // 感覺相當於將Handle對象分成了多類,每類通過自己的HandlerAdapter執行Handler對象中的處理方法,這樣每類的執行方式都一樣 handlerAdapter.handler(myHttpRequestHandler); } /** * 通過Handler獲取對應的HandlerAdapter進行適配 * @param myHandler * @return */ public MyHandlerAdapter getHandlerAdapter(MyHandler myHandler) { if (null != this.myHandlerAdapters) { for (MyHandlerAdapter myHandlerAdapter : myHandlerAdapters) { if (myHandlerAdapter.support(myHandler)) { return myHandlerAdapter; } } } throw new RuntimeException("該Handler沒有對應的HandlerAdapter"); } public static void main(String[] args) { MyDispatcherServlet myDispatcherServlet = new MyDispatcherServlet(); myDispatcherServlet.doDispatcher("url"); } }
-
-
注意事項:
- 三種命名方式,是根據src是以怎樣的形式給到Adapter(在 Adapter 里的形式)來命名的
- 類適配器:以類給到,在Adapter里,就是將src當做類,繼承
- 對象適配器:以對象給到,在Adapter里,將src作為一個對象,持有
- 介面適配器:以介面給到,在Adapter里,將src作為一個介面,實現
- Adapter模式最大的作用還是將原本不兼容的介面融合在一起工作
- 實際開發中,實現起來不拘泥於我們講解的三種經典形式