定義
將一個接口轉(zhuǎn)換成客戶希望的另一個接口,使接口不兼容的那些類可以一起工作壁榕,其別名為包裝器(Wrapper)矛紫。適配器模式既可以作為類結(jié)構(gòu)型模式,也可以作為對象結(jié)構(gòu)型模式牌里。
關(guān)于適配器模式的定義如上已經(jīng)很清楚了颊咬,下面這幅圖可以更清楚的幫助我們理解適配器模式。
適配器作為一個中間件牡辽,將兩個不兼容的類鏈接起來喳篇。
根據(jù)適配器與被適配者類的關(guān)系不同,適配器模式可分為對象適配器和類適配器态辛,在對象適配器模式中麸澜,適配器與適配者之間是關(guān)聯(lián)關(guān)系,在類適配器模式中因妙,適配器與適配者之間是繼承(或?qū)崿F(xiàn))關(guān)系痰憎。
對象適配器模式
UML
適配器模式主要有下面幾個角色:
- 目標類(Target):目標類定義客戶所需的接口,可以是一個接口攀涵、抽象類或者是一個具體類铣耘。
- 被適配者類(Adaptee):需要被適配的類,它有自己的方法以故,但不能被目標類直接調(diào)用蜗细,需要通過適配器進行適配。
- 適配器類(Adapter):通過適配器類對Target和Adaptee進行適配怒详。
前面說過炉媒,對象適配器與類適配器之間的區(qū)別就是,適配器與被適配者之間的關(guān)系昆烁,這里對象適配器中吊骤,適配器與被適配者之間是關(guān)聯(lián)關(guān)系。
適配器的主要代碼如下:
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter() {
this.adaptee = new Adaptee();
}
@Override
public void request() {
adaptee.specificRequest();
}
}
類適配器模式
UML
可以看到這里與前面對象適配器的區(qū)別就是適配器與被適配者之間是繼承(或?qū)崿F(xiàn))關(guān)系静尼。
代碼表示如下
public class Adapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest();
}
}
由于在Java中是單繼承的白粉,所以這種類適配器模式的使用會受到限制,如果Target不是接口鼠渺,而是具體類鸭巴,就無法使用類適配器模式了,所以在Java中大部分情況下還是使用對象適配器更多一點拦盹。
實例
還是通過一個實例來理解吧:
軟件公司OA系統(tǒng)需要提供一個加密模塊鹃祖,將用戶機密信息(如口令、郵箱等)加密之后再存儲在數(shù)據(jù)庫中普舆,系統(tǒng)已經(jīng)定義好了數(shù)據(jù)庫操作類恬口。為了提高開發(fā)效率,現(xiàn)需要重用已有的加密算法奔害,這些算法封裝在一些由第三方提供的類中楷兽,有些甚至沒有源代碼。試使用適配器模式設(shè)計該加密模塊华临,實現(xiàn)在不修改現(xiàn)有類的基礎(chǔ)上重用第三方加密方法芯杀。
UML
根據(jù)需求我們可以規(guī)劃結(jié)構(gòu)圖如下:
代碼
主要代碼如下
//加密的工具類
public class EncryptUtils {
public String MD5Encrypt(String str) {
String encode = null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
BASE64Encoder base64Encoder = new BASE64Encoder();
encode = base64Encoder.encode(md5.digest(str.getBytes()));
return encode;
} catch (NoSuchAlgorithmException e) {
System.out.println("加密出錯");
return null;
}
}
public String DESEncrypt(String str) {
String password = "01234567";
String encode = null;
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password.getBytes());
//創(chuàng)建一個密匙工廠,然后用它把DESKeySpec轉(zhuǎn)換成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
//Cipher對象實際完成加密操作
Cipher cipher = Cipher.getInstance("DES");
//用密匙初始化Cipher對象
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
//現(xiàn)在雅潭,獲取數(shù)據(jù)并加密
//正式執(zhí)行加密操作
byte[] bytes = cipher.doFinal(str.getBytes());
BASE64Encoder base64Encoder = new BASE64Encoder();
encode = base64Encoder.encode(bytes);
return encode;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
public String RSAEncrypt(String str) {
return "實現(xiàn)RSA加密返回 ->_->";
}
}
//目標類
public abstract class EncryptModel {
abstract String userEncrypt(String str);
}
適配器類
public class EncryptAdapter extends EncryptModel {
private EncryptUtils encryptUtils;
public EncryptAdapter() {
this.encryptUtils = new EncryptUtils();
}
@Override
String userEncrypt(String str) {
return encryptUtils.MD5Encrypt(str);
}
}
客戶端代碼
public class Client {
public static void main(String[] args) {
EncryptModel encryptModel;
encryptModel = new EncryptAdapter();
String encode = encryptModel.userEncrypt("userName");
System.out.println("加密后的數(shù)據(jù)為:" + encode);
}
}
運行結(jié)果
加密后的數(shù)據(jù)為:Q14GSNY0F1xGvUCsNmVFqA==
成功通過適配器類使客戶端調(diào)用加密工具類中的加密算法揭厚。
變種--缺省適配器
缺省適配器是適配器模式的一個邊種,在Java中使用也挺廣泛的扶供。
定義
當不需要實現(xiàn)一個接口所提供的所有方法時筛圆,可先設(shè)計一個抽象類實現(xiàn)該接口,并為接口中每個方法提供一個默認實現(xiàn)(空方法)椿浓,那么該抽象類的子類可以選擇性地覆蓋父類的某些方法來實現(xiàn)需求太援,它適用于不想使用一個接口中的所有方法的情況闽晦,又稱為單接口適配器模式。
UML
在Java開發(fā)中我們應(yīng)該都遇到過這種情況提岔,一個接口仙蛉,定義了N種方法,當你使用的時候碱蒙,又僅僅需要使用接口中的一兩個方法荠瘪,但你卻必須實現(xiàn)這個接口中的所有方法,寫了很長一段無意義的代碼赛惩。缺省適配器就是為了解決這種情況哀墓,它通過定一個抽象類實現(xiàn)原始接口,實現(xiàn)接口中的所有方法喷兼,并給所有方法一個默認值或操作篮绰。當需要使用的時候,只需要定義一個類繼承這個抽象類季惯,重寫你所需要的一兩個方法即可阶牍。這個抽象類就是一個缺省適配器。
代碼
原始接口
public interface InterfaceService {
void serviceOperation1();
String serviceOperation2();
int serviceOperation3();
void serviceOperation4();
}
缺省適配器
public abstract class ServiceAdapter implements InterfaceService {
@Override
public void serviceOperation1() {
}
@Override
public String serviceOperation2() {
return null;
}
@Override
public int serviceOperation3() {
return 0;
}
@Override
public void serviceOperation4() {
}
}
具體實現(xiàn)類
public class ConcreteService extends ServiceAdapter {
@Override
public void serviceOperation1() {
System.out.println("serviceOperation1");
}
}
小結(jié)
適配器模式應(yīng)該是非常常見的一種設(shè)計模式了星瘾,作為Android開發(fā)工程師走孽,我們最常見的應(yīng)該就是各種適配器了,例如ListView和RecycleView的適配器琳状。適配器模式將現(xiàn)有接口轉(zhuǎn)換為客戶端所期望的接口磕瓷,實現(xiàn)了對現(xiàn)有類的復(fù)用。