文章目錄
- 1. 項目需求分析
-
- 1.1 顯示生活中的例子
- 2. 什麼是擴充卡模式?
- 3. 擴充卡模式的工作原理
- 4. 類擴充卡
-
- 4.1 類擴充卡基本介紹
- 4.2 類擴充卡模式應用執行個體
- 4.2 用類圖來描述
- 4.3 上代碼
-
- 4.3.1 被擴充卡類
- 4.3.2 适配接口
- 4.3.3 擴充卡類
- 4.3.4 手機類,使用擴充卡
- 4.3.5 測試類
- 4.3.6 運作結果
- 4.4 類擴充卡模式注意事項和細節
-
- 4.4.1 缺點
- 4.4.2 優點
- 5. 對象擴充卡
-
- 5.1 對象擴充卡模式介紹
- 5.2 用類圖來描述
- 5.3 上代碼
-
- 5.3.1 改進擴充卡類
- 5.3.2 修改測試類,其他類不變
- 5.3.3 運作結果
- 5.4 對象擴充卡模式注意事項和細節
- 6. 接口擴充卡模式
-
- 6.1 接口擴充卡模式介紹
- 6.2 用類圖來描述
- 6.3 上代碼
-
- 6.3.1 接口
- 6.3.2 抽象擴充卡,實作所有方法
- 6.3.3 測試類
- 6.3.4 運作結果
- 7. 擴充卡在SpringMVC架構應用的源碼分析
-
- 7.1 SpringMvc的HandlerAdapter,就使用了擴充卡模式。
-
- 7.1.1 DispatcherServlet類
- 8. 手寫SpringMvc通過擴充卡設計模式擷取對應Controller的源碼。
-
- 8.1 用類圖來描述
- 8.2 上代碼
-
- 8.2.1 controller類
- 8.2.2 擴充卡類
- 8.2.3 DispatchServlet類
- 8.2.4 運作結果
- 9. 擴充卡模式的注意事項和細節
1. 項目需求分析
1.1 顯示生活中的例子
假如去泰國旅遊,泰國的插座都是兩孔的(歐标),而我們國家的插座但是三孔的,于是可以買個多功能轉換插頭(擴充卡),這樣就可以使用了。
2. 什麼是擴充卡模式?
- 擴充卡模式(Adapter Pattern)将某個類的接口轉換成用戶端期望的另一個接口表示,主要目的是相容性,讓原本因接口不比對而不能在一起工作的兩個類可以協同工作。其别名為包裝器(Wrapper)
- 擴充卡模式屬于結構型模式。
- 主要分為3類:擴充卡模式、對象擴充卡模式、接口擴充卡模式。
3. 擴充卡模式的工作原理
- 擴充卡模式:将一個類接口轉換成另一種接口,讓原本接口不相容的類可以相容。
- 從使用者的角度看不到被适配者,是解耦的。
- 使用者調用擴充卡轉化出來的目标接口方法,擴充卡再調用被适配者的相關接口方法。
- 使用者收到回報結果,感覺隻是和目标接口互動,如圖
4. 類擴充卡
4.1 類擴充卡基本介紹
Adapter類,通過繼承src類,實作dst類接口,完成src->dst的适配。
4.2 類擴充卡模式應用執行個體
- 以生活中充電器的例子來講解擴充卡,充電器本身相當于Adapter,220V交流電相當于src(即被适配者),我們的dst(即 目标)是5V直流電。
4.2 用類圖來描述
4.3 上代碼
4.3.1 被擴充卡類
/**
* @author LongXi
* @create 2021-08-11 21:11
*/
//被擴充卡類
public class Voltage220V {
public int output220V(){
int src = 220;
System.out.println("電壓="+ src + "伏");
return src;
}
}
4.3.2 适配接口
/**
* @author LongXi
* @create 2021-08-11 21:13
*/
//适配接口
public interface IVoltage5V {
public int output5V();
}
4.3.3 擴充卡類
/**
* @author LongXi
* @create 2021-08-11 21:14
*/
//擴充卡類
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
//擷取220V電壓
int srcV = output220V();
//轉成5V
int dstV = srcV / 44;
return dstV;
}
}
4.3.4 手機類,使用擴充卡
/**
* @author LongXi
* @create 2021-08-11 21:17
*/
public class Phone {
//充電
public void charging(IVoltage5V iVoltage5V){
if (iVoltage5V.output5V() == 5){
System.out.println("電壓為5V,可以充電~~");
} else if (iVoltage5V.output5V() > 5){
System.out.println("電壓大于5V,不能充電~~");
}
}
}
4.3.5 測試類
/**
* @author LongXi
* @create 2021-08-11 21:21
*/
public class Client {
public static void main(String[] args) {
System.out.println("類擴充卡模式");
Phone phone = new Phone();
phone.charging(new VoltageAdapter());
}
}
4.3.6 運作結果
電壓=220伏
電壓為5V,可以充電~~
4.4 類擴充卡模式注意事項和細節
4.4.1 缺點
- Java是單繼承機制,是以類擴充卡需要繼承src類,至一點算是一個缺點,因為這要求dst必須是接口,有一定局限性。
- src類方法在Adapter中都會暴露出來,也增加了使用的成本(output220V)。
4.4.2 優點
由于其繼承了src類,是以它可以根據需求重寫src類的方法,是的Adapter的靈活性增強了。
5. 對象擴充卡
5.1 對象擴充卡模式介紹
- 基本思路和類擴充卡模式相同,隻是将Adapter類作為修改,不是繼承src類,而是持有src類執行個體,以解決相容性的問題。即:持有src類,實作dst類接口,完成src->dst的适配。
- 根據“合成服用原則”,在系統中盡量使用關聯關系來替代繼承關系。
- 對象擴充卡模式是擴充卡模式常用的一種。
- 改進思路:隻需改進擴充卡即可。
5.2 用類圖來描述
5.3 上代碼
5.3.1 改進擴充卡類
**
* @author LongXi
* @create 2021-08-11 21:14
*/
//擴充卡類
public class VoltageAdapter implements IVoltage5V {
//關聯關系中的聚合關系
private Voltage220V voltage220V;
public VoltageAdapter(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public int output5V() {
int dst = 0;
if (null != voltage220V){
//擷取220V電壓
int src = voltage220V.output220V();
System.out.println("使用對象擴充卡,進行适配~");
dst = src/44;
System.out.println("适配完成,輸出電壓為:" + dst);
}
return dst;
}
}
5.3.2 修改測試類,其他類不變
/**
* @author LongXi
* @create 2021-08-11 21:21
*/
public class Client {
public static void main(String[] args) {
System.out.println("對象擴充卡模式");
Phone phone = new Phone();
phone.charging(new VoltageAdapter(new Voltage220V()));
}
}
5.3.3 運作結果
對象擴充卡模式
電壓=220伏
使用對象擴充卡,進行适配~
适配完成,輸出電壓為:5
電壓為5V,可以充電~~
5.4 對象擴充卡模式注意事項和細節
- 對象擴充卡和類擴充卡其實算是同一種思想,隻不過實作方式不同。根據合成複用原則,使用組合替代繼承,是以它解決了類擴充卡必須繼承src的局限性問題,也不再要求dst必須是接口。
- 使用成本更低,更靈活。
6. 接口擴充卡模式
6.1 接口擴充卡模式介紹
- 一些書籍稱為:擴充卡模式(Default Adapter Pattern)或預設擴充卡模式。
- 當不需要全部實作接口提供的方法時,可先設計一個抽象類實作接口,并為該接口中每個方法提供一個預設實作(空方法),那麼該抽象類的子類可有選擇的覆寫父類的某些方法來實作需求。
- 适用于一個接口不想使用其所有的方法的情況。
6.2 用類圖來描述
6.3 上代碼
6.3.1 接口
/**
* @author LongXi
* @create 2021-08-11 22:10
*/
public interface InterFace4 {
public void m1();
public void m2();
public void m3();
public void m4();
}
6.3.2 抽象擴充卡,實作所有方法
/**
* @author LongXi
* @create 2021-08-11 22:11
*/
//在AbsAdapter類中,我們将InterFace4的方法進行預設實作
public abstract class AbsAdapter implements InterFace4{
@Override
public void m1() {
}
@Override
public void m2() {
}
@Override
public void m3() {
}
@Override
public void m4() {
}
}
6.3.3 測試類
/**
* @author LongXi
* @create 2021-08-11 22:13
*/
public class Client {
public static void main(String[] args) {
AbsAdapter absAdapter = new AbsAdapter() {
//隻需要去覆寫我們需要使用的接口方法
@Override
public void m1() {
System.out.println("覆寫了m1方法");
}
};
absAdapter.m1();
}
}
6.3.4 運作結果
覆寫了m1方法
7. 擴充卡在SpringMVC架構應用的源碼分析
7.1 SpringMvc的HandlerAdapter,就使用了擴充卡模式。
7.1.1 DispatcherServlet類
8. 手寫SpringMvc通過擴充卡設計模式擷取對應Controller的源碼。
- Spring定義了一個擴充卡接口,是的每一種Contrller有一種對應的擴充卡實作類
- 擴充卡代替controller執行相應的方法。
- 擴充Controller時,隻需要增加一個擴充卡類就完成了SpringMvc的擴充了。
- 就是設計模式的力量。
8.1 用類圖來描述
8.2 上代碼
8.2.1 controller類
/**
* @author LongXi
* @create 2021-08-12 20:49
*/
public interface Controller {
}
class HttpController implements Controller{
public void doHttpHandler(){
System.out.println("http...");
}
}
class SimpleController implements Controller{
public void doSimpleHandler(){
System.out.println("Simple...");
}
}
class AnnotationController implements Controller{
public void doAnnotationHandler(){
System.out.println("Annotation...");
}
}
8.2.2 擴充卡類
/**
* @author LongXi
* @create 2021-08-12 20:53
*/
//定義了Adapter接口
public interface HandlerAdapter {
public boolean supports(Object handler);
public void handler(Object handler);
}
//多種擴充卡
class SimpleHandlerAdapter implements HandlerAdapter{
@Override
public boolean supports(Object handler) {
return (handler instanceof SimpleController);
}
@Override
public void handler(Object handler) {
((SimpleController)handler).doSimpleHandler();
}
}
class HttpHandlerAdapter implements HandlerAdapter{
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpController);
}
@Override
public void handler(Object handler) {
((HttpController)handler).doHttpHandler();
}
}
class AnnotationHandlerAdapter implements HandlerAdapter{
@Override
public boolean supports(Object handler) {
return (handler instanceof AnnotationController);
}
@Override
public void handler(Object handler) {
((AnnotationController)handler).doAnnotationHandler();
}
}
8.2.3 DispatchServlet類
/**
* @author LongXi
* @create 2021-08-12 21:00
*/
public class DispatchServlet {
public List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();
public DispatchServlet() {
handlerAdapters.add(new HttpHandlerAdapter());
handlerAdapters.add(new SimpleHandlerAdapter());
handlerAdapters.add(new AnnotationHandlerAdapter());
}
public void doDispatch(){
//此處模拟SpringMvc從request取handler的對象。
//擴充卡可以擷取到希望的Controller
HttpController httpController = new HttpController();
// SimpleController simpleController = new SimpleController();
// AnnotationController annotationController = new AnnotationController();
//得到對應擴充卡
HandlerAdapter adapter =getHandler(httpController);
// 通過擴充卡執行對應的controller所對應的方法
adapter.handler(httpController);
}
public HandlerAdapter getHandler(Controller controller){
for (HandlerAdapter adapter:this.handlerAdapters){
if (adapter.supports(controller)){
return adapter;
}
}
return null;
}
public static void main(String[] args) {
new DispatchServlet().doDispatch();
}
}
8.2.4 運作結果
9. 擴充卡模式的注意事項和細節
- 三種命名方式:是根據src是以怎麼樣的形式給到Adapter(在Adapter裡的形式)來命名的。
-
類擴充卡:以類給到,在Adapter裡,就是将src當作類,繼承。
對象擴充卡:以對象給到,在Adapter裡,将src作為一個對象,持有。
接口擴充卡:以接口給到,在Adapter裡,将src作為一個接口,實作。
- Adapter模式最大的作用還是将原本不相容的接口融合在一起工作。
- 實際開發中,實作起來不拘泥我們講解的三種經典形式。