適配器模式

(一)需求場景

現實生活中,手機或者電腦充電,如果需要充電,需要電源適配器進行連接,以保證電壓能夠得到轉換,滿足對應設備所需電流的使用. 就拿生活中最常見的:手機充電,因爲有手機電源適配器才能正常充電,保證電流不會過大接入到手機造成危險
在這裏插入圖片描述

(二)基本介紹

1: 適配器模式(Adapter Pattern)將某個類的接口轉換成客戶端期望的另一個接口表示,主要的目的是兼容性,讓原本因接口不匹配不能一起工作的兩個類可以協同
工作。其別名爲包裝器(Wrapper)
2: 適配器模式屬於結構型模式
3: 主要分爲三類:類適配器模式、對象適配器模式、接口適配器模式

(三)工作原理

適配器模式:將一個類的接口轉換成另一種接口.讓原本接口不兼容的類可以兼容
1: 從用戶的角度看不到被適配者,是解耦的
2: 用戶調用適配器轉化出來的目標接口方法,適配器再調用被適配者的相關接口
方法
3:用戶收到反饋結果,感覺只是和目標接口交互,如下圖
4:簡單來說我們所要做的就是將源數據進行轉換,經過適配器轉換成我們需要的數據

在這裏插入圖片描述

(四)類適配器模式

類適配器模式主要是Adapter類,通過繼承 src類,實現 dst 類接口,完成src->dst的適配。在下面實例中,我們需要完成手機充電,由於不能直接使用220V電壓,因此需要進行轉換,創建一個適配器將220V電壓轉換爲5V電壓,然後手機進行充電。
適配器模式它的理解之處在於,適配器類通過繼承源數據類,擁有基本的電源接入即獲取了源數據,此時需要進行轉換工作,因此需要實現5V接口,實現方法完成轉換工作,如果還需要爲電腦使用則可以再次構建一個12V的接口實現對應方法,此時整體就變成了單個數據源,可以擴展多種不同的適配設備.
在這裏插入圖片描述

//源電壓類
public class Voltage220V {

    int output220V() {
        System.out.println("輸出220V電壓");
        return 220;
    }
}
public interface Voltage5V {

    int output5V();

}
public interface Voltage12V {
    int output12V();
}
public class VoltageAdapter extends Voltage220V implements Voltage5V, Voltage12V {

    //將220V電壓轉換成5V電壓
    @Override
    public int output5V() {
        //獲取源電壓數據,即適配器先連接220V的插座
        int output = output220V();
        //這裏就是模擬適配進行了內部電壓轉換,將220V電壓轉換成了5V
        output = 5;
        return output;
    }

    //將220V電壓轉換成12V電壓
    @Override
    public int output12V() {
        //獲取源電壓數據,即適配器先連接220V的插座
        int output = output220V();
        //這裏就是模擬適配進行了內部電壓轉換,將220V電壓轉換成了12V
        output = 12;
        return output;
    }
}
public class IPhone {

    //手機的充電功能,只能接收5V的電壓
    void charging(Voltage5V voltage5V) {
        //獲取接入的電流
        int output = voltage5V.output5V();
        if (output > 5) {
            System.out.println("電壓過高");
        } else {
            System.out.println("手機正在充電,當前電壓" + output + "伏");
        }
    }
}
public class Computor {

    //電腦的充電功能,只能接收12V的電壓
    void charging(Voltage12V voltage12V) {
        //獲取接入的電流
        int output = voltage12V.output12V();
        if (output == 12) {
            System.out.println("電腦正在充電,當前電壓" + output + "伏");
        } else {
            System.out.println("電壓不符");
        }
    }
}
public class Main {

    public static void main(String[] args) {
        //手機充電
        IPhone iPhone = new IPhone();
        //購置一個適配器
        VoltageAdapter voltageAdapter = new VoltageAdapter();
        //手機使用適配器充電
        iPhone.charging(voltageAdapter);
        //電腦充電
        Computor computor = new Computor();
        computor.charging(voltageAdapter);
    }
}

在這裏插入圖片描述

(五)對象適配器

基本思路和類的適配器模式相同,只是將Adapter類作修改,不是繼承src類,而
是持有src類的實例,以解決兼容性的問題。 即:持有 src類,實現 dst 類接口,
完成src->dst的適配,對象適配器好處在於使用組合代替了繼承,而且使得我們可以轉換的數據源不止一個增強的轉換器的功能

相較於類適配器代碼,對象適配器只修改了適配器類繼承關係,持有一個Voltage220V 類實例,提供一個構造方法賦值,其他的與之前沒有差別

public class VoltageAdapter implements Voltage5V, Voltage12V {

    private Voltage220V output220V;

    public VoltageAdapter(Voltage220V output220V) {
        this.output220V = output220V;
    }

    //將220V電壓轉換成5V電壓
    @Override
    public int output5V() {
        //獲取源電壓數據,即適配器先連接220V的插座
        int output = output220V.output220V();
        //這裏就是模擬適配進行了內部電壓轉換,將220V電壓轉換成了5V
        output = 5;
        return output;
    }

    //將220V電壓轉換成12V電壓
    @Override
    public int output12V() {
        //獲取源電壓數據,即適配器先連接220V的插座
        int output = output220V.output220V();
        //這裏就是模擬適配進行了內部電壓轉換,將220V電壓轉換成了12V
        output = 12;
        return output;
    }
}
(六)接口適配器

當不需要全部實現接口提供的方法時,可先設計一個抽象類實現接口,併爲該接
口中每個方法提供一個默認實現(空方法),那麼該抽象類的子類可有選擇地覆
蓋父類的某些方法來實現需求.
接口適配器是對接口實現的一種優化,此種方法不僅僅適用於適配器,對於其他涉及到接口的部分也適合,如果我們需要實現的接口方法過多但是真正使用的方法只有個別,那麼我們可以提供一個抽象類去實現接口,然後實現用空方法體去實現每個方法,然後如果我們需要用到接口只需要new 抽象類即可,然後選擇性去實現對應的單個或多個方法

比如現在有個接口:

public interface Voltage {
    void run1();

    void run2();

    void run3();

    void run4();
}

現在需要創建一個抽象類,實現所有方法,空方法體

public abstract  class AbstractVoltage  implements  Voltage {

    @Override
    public void run1() { }

    @Override
    public void run2() { }

    @Override
    public void run3() { }

    @Override
    public void run4() { }
}

上面已經創建接口和抽象類,那麼現在就需要實際使用了,但是我現在只想要接口的run3來幫助我完成某項任務

public class Main {
    public static void main(String[] args) {
        //現在需要使用Voltage接口的run3方法
        new AbstractVoltage() {
            @Override
            public void run3() {
                System.out.println("執行Run3任務");
            }
        };
    }
}

這種方式適用於一個接口不想使用其所有的方法的情況,它的使用範圍很廣

(七)應用實例

適配器模式在SpringMVC框架應用的源碼剖析

  1. SpringMvc中的HandlerAdapter, 就使用了適配器模式
  2. SpringMVC處理請求的流程回顧
  3. 使用HandlerAdapter 的原因分析:
    可以看到處理器的類型不同,有多重實現方式,那麼調用方式就不是確定的,如果需要直接調Controller方法,需要調用的時候就得不斷是使用if else來進行判斷是哪一種子類然後執行。那麼如果後面要擴展Controller,就得修改原來的代碼,這樣違背了OCP開閉原則

Spring-MVC中關於適配器最核心的代碼就是下面這個,web.xml配置的
DispatcherServlet 根據請求來映射到處理器,通過不同的適配器指定不同的處理器來處理,調用對應的處理方法然後返回ModelAndView

public class DispatcherServlet extends FrameworkServlet {
// 通過HandlerMapping來映射Controller
mappedHandler = getHandler(processedRequest);
//獲取適配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//..
// 通過適配器調用controller的方法並返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}

下面貼上學習參考的SpringMVC中關於適配器的參考代碼(來源於韓順平老師PPT)
下列代碼主要有三個角色,處理器Controller接口,以及實現了該接口的不同類型處理器,還有控制轉發器DispatcherServlet ,還有適配器,通過適配器完成對不同請求類型進行的不同處理器處理

//多種Controller實現  
public interface Controller {

}

class HttpController implements Controller {
	public void doHttpHandler() {
		System.out.println("http...");
	}
}

class SimpleController implements Controller {
	public void doSimplerHandler() {
		System.out.println("simple...");
	}
}

class AnnotationController implements Controller {
	public void doAnnotationHandler() {
		System.out.println("annotation...");
	}
}


import java.util.ArrayList;
import java.util.List;

public class DispatchServlet {

	public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();

	public DispatchServlet() {
		handlerAdapters.add(new AnnotationHandlerAdapter());
		handlerAdapters.add(new HttpHandlerAdapter());
		handlerAdapters.add(new SimpleHandlerAdapter());
	}

	public void doDispatch() {

		// 此處模擬SpringMVC從request取handler的對象,
		// 適配器可以獲取到希望的Controller
		 HttpController controller = new HttpController();
		// AnnotationController controller = new AnnotationController();
		//SimpleController controller = new SimpleController();
		// 得到對應適配器
		HandlerAdapter adapter = getHandler(controller);
		// 通過適配器執行對應的controller對應方法
		adapter.handle(controller);

	}

	public HandlerAdapter getHandler(Controller controller) {
		//遍歷:根據得到的controller(handler), 返回對應適配器
		for (HandlerAdapter adapter : this.handlerAdapters) {
			if (adapter.supports(controller)) {
				return adapter;
			}
		}
		return null;
	}

	public static void main(String[] args) {
		new DispatchServlet().doDispatch(); // http...
	}

}


///定義一個Adapter接口 
public interface HandlerAdapter {
	public boolean supports(Object handler);

	public void handle(Object handler);
}

// 多種適配器類

class SimpleHandlerAdapter implements HandlerAdapter {

	public void handle(Object handler) {
		((SimpleController) handler).doSimplerHandler();
	}

	public boolean supports(Object handler) {
		return (handler instanceof SimpleController);
	}

}

class HttpHandlerAdapter implements HandlerAdapter {

	public void handle(Object handler) {
		((HttpController) handler).doHttpHandler();
	}

	public boolean supports(Object handler) {
		return (handler instanceof HttpController);
	}

}

class AnnotationHandlerAdapter implements HandlerAdapter {

	public void handle(Object handler) {
		((AnnotationController) handler).doAnnotationHandler();
	}

	public boolean supports(Object handler) {

		return (handler instanceof AnnotationController);
	}

}

測試:
通過執行DispatchServlet 中的doDispatchServlet()來對不同請求類型進行處理然後映射到對應的適配器,遍歷適配器通過supports匹配到對應的handler 處理器,然後執行適配器對象的handle去執行各個類型處理器的處理任務方法,完成請求的映射和處理

發佈了64 篇原創文章 · 獲贊 9 · 訪問量 5002
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章