1. 程式人生 > >適配器模式(三種)簡單使用

適配器模式(三種)簡單使用

減少 port 必須 手機 包裝 統一 override 我們 b-

前言

適配器模式是將一個類的接口轉換成客戶希望的另外一個接口,身邊很多東西都是適用於適配器模式的,筆記本的電源(也叫電源適配器),是將220V的交流電轉換為筆記本電腦所需要的12V(電流先忽略),筆記本電腦的各種接口,VGA轉Hdml,USB-TypeA 轉 USB-TypeC,亦或者你在香港買了個手機,充電器是你生活中沒見過的三孔插座通過一個轉換頭轉換為國內常用的插頭,很多例子都能很形象的解釋這個設計模式。適配器模式(有時候也稱包裝樣式或者包裝)將一個類的接口適配成用戶所期待的。一個適配允許通常因為接口不兼容而不能在一起工作的類工作在一起,做法是將類自己的接口包裹在一個已存在的類中。
UML角色

Source:需要被適配的類、接口、對象,即Datas。

Destination:需要得到的類,Source通過適配得到的類對象,也就是我們期待得到的借口。
Adapter:適配器類,協調Source和Destination,使兩者能夠協同工作。
適用場景

1,系統需要使用現有的類,但現有的類卻不兼容。
2,需要建立一個可以重復使用的類,用於一些彼此關系不大的類,並易於擴展,以便於面對將來會出現的類。
3,需要一個統一的輸出接口,但是輸入類型卻不可預知。
Demo

簡單的抽象一個場景:手機充電需要將220V的交流電轉化為手機鋰電池需要的5V直流電,我們的demo就是寫一個電源適配器,將 AC220v ——> DC5V,其實適配器模式可以簡單的分為三類:類適配器模式、對象的適配器模式、接口的適配器模式。我們就以這三種模式來實現上述步驟。
類適配器模式

就上面提到的功能,簡單的使用類適配器模式,Source類如下:

package com.demo.adapter.classadapter;

/**
* Created by italkbb on 2018/1/24.
*/

public class AC220 {
public int output220V(){
int output = 220;
return output;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13

我們的目標類Destination,只需要定義方法,由適配器來轉化:

package com.demo.adapter.classadapter;

/**
* Created by italkbb on 2018/1/24.
*/

public interface DC5 {
int output5V();
}

1
2
3
4
5
6
7
8
9
10

Adapter類如下:

package com.demo.adapter.classadapter;

/**
* Created by italkbb on 2018/1/24.
*/

public class PowerAdapter extends AC220 implements DC5 {
@Override
public int output5V() {
int output = output220V();
return (output / 44);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14

對於使用,也很簡單:

/**
* 類適配器使用demo
*/
private void initClassAdapter() {
DC5 dc5 = new com.demo.adapter.classadapter.PowerAdapter();
dc5.output5V();
}

1
2
3
4
5
6
7
8

因為java單繼承的緣故,Destination類必須是接口,以便於Adapter去繼承Source並實現Destination,完成適配的功能,但這樣就導致了Adapter裏暴露了Source類的方法,使用起來的成本就增加了。
對象適配器模式

對於同樣的邏輯,我們在以對象適配器模式實現。我們保留AC220和DC5兩個基本類,我們讓Adapter持有Destination類的實例,然後再實現DC5,以這種持有對象的方式來實現適配器功能:

package com.demo.adapter.objadapter;

import com.demo.adapter.classadapter.AC220;
import com.demo.adapter.classadapter.DC5;

/**
* Created by italkbb on 2018/1/24.
*/

public class PowerAdapter implements DC5{
private AC220 mAC220;

public PowerAdapter(AC220 ac220){
this.mAC220 = ac220;
}

@Override
public int output5V() {
int output = 0;
if (mAC220 != null) {
output = mAC220.output220V() / 44;
}
return output;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

使用代碼:

/**
* 對象適配器模式demo
*/
private void initObjAdapter() {
com.demo.adapter.objadapter.PowerAdapter adapter = new com.demo.adapter.objadapter.PowerAdapter(new AC220());
adapter.output5V();
}

1
2
3
4
5
6
7
8

對象適配器和類適配器其實算是同一種思想,只不過實現方式不同。再回想裝飾者模式,裝飾者是對Source的裝飾,使用者毫無察覺到Source被裝飾,也就是用法不變。而對於適配器模式用法還是有改變的。
接口適配器模式

對於接口適配器模式,我們就不用擔著眼於220->5,我們的接口可以有更多的抽象方法,這一點在android開發中有很多影子,動畫的適配器有很多接口,但我們只需要關心我們需要的回調方法(詳見AnimatorListenerAdapter類),我們把接口比作萬能適配器:

package com.demo.adapter.interfaceadapter;

/**
* Created by italkbb on 2018/1/24.
*/

public interface DCOutput {
int output5V();
int output9V();
int output12V();
int output24V();
}

1
2
3
4
5
6
7
8
9
10
11
12
13

然後我們要用的是5V的電壓,所以關心5V的適配:

package com.demo.adapter.interfaceadapter;

import com.demo.adapter.classadapter.AC220;

/**
* Created by italkbb on 2018/1/24.
*/

public class Power5VAdapter extends PowerAdapter {

public Power5VAdapter(AC220 ac220) {
super(ac220);
}

@Override
public int output5V() {
int output = 0;
if (mAC220 != null) {
output = mAC220.output220V() / 44;
}
return output;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

但是我們必須存在一個中間適配器,用於實現默認的接口方法,以至於減少我們適配器的代碼量,讓代碼更加清晰:

package com.demo.adapter.interfaceadapter;

import com.demo.adapter.classadapter.AC220;

/**
* Created by italkbb on 2018/1/24.
* 這裏抽象類其實就寫了空方法,等著子類去實現需要的方法。
*/
public abstract class PowerAdapter implements DCOutput{
protected AC220 mAC220;

public PowerAdapter(AC220 ac220){
this.mAC220 = ac220;
}

@Override
public int output5V() {
return mAC220.output220V();
}

@Override
public int output9V() {
return mAC220.output220V();
}

@Override
public int output12V() {
return mAC220.output220V();
}

@Override
public int output24V() {
return mAC220.output220V();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

這樣一來我們就只需要重寫父類我們關心的方法了,當然我們有時候可以省略Power5VAdapter類,因為內部類可以實現我們的方法,就跟使用setOnClickOnLintener(new OnClickOnLintener(){…})一樣,我們來看使用:

/**
* 接口適配器模式demo
*/
private void initinterfaceAdapter() {
// 已經實現了子類
com.demo.adapter.interfaceadapter.Power5VAdapter power5VAdapter = new Power5VAdapter(new AC220());
power5VAdapter.output5V();

// 直接實現子類
com.demo.adapter.interfaceadapter.PowerAdapter powerAdapter = new PowerAdapter(new AC220()) {
@Override
public int output5V() {
int output = 0;
if (mAC220 != null) {
output = mAC220.output220V() / 44;
}
return output;
}
};
powerAdapter.output5V();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

這樣也實現了這個適配功能,而且可以說易於擴展。
總結

可以說Source的存在形式決定了適配器的名字,類適配器就是繼承Source類,對象適配器就是持有Source類,接口適配器就是實現Source接口。
後記

android開發中,ListView、RecyclerView等列表展示組件填充數據都會用到Adapter,這裏面的Source相當於Datas,Destination相當於Views,然後Adapter去協調數據與顯示。使用適配器模式會擁有更高的復用性以及更好的擴展性,但是過多的使用適配器模式,代碼的可閱讀性會有所下降,但是設計模式應該是對於相對應的情況,而不是盲目的使用。
---------------------
作者:Must_Do_Kaihong
來源:CSDN
原文:https://blog.csdn.net/u012359453/article/details/79165080
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

適配器模式(三種)簡單使用