1. 適配器模式介紹
1.1 適配器模式介紹
適配器模式(adapter pattern)的原始定義是:將一個類的接口轉換為客戶期望的另一個接口,適配器可以讓不兼容的兩個類一起協同工作。
適配器模式的主要作用是把原本不兼容的接口,通過適配修改做到統一,使得用戶方便使用。比如,萬能充電器和多接口數據線都是為了適配各種不同的接口。
為什么要轉換接口?
- 原接口和目標接口都已經存在,不易修改接口代碼。
- 抽象接口希望復用已有組件的邏輯。
1.2 適配器模式結構
適配器模式(Adapter)包含以下主要角色:
- 目標(Target)接口:當前系統業務所期待的接口,它可以是抽象類或接口。
- 適配者(Adaptee)類:被適配的角色,它是被訪問和適配的現存組件庫中的組件接口。
- 適配器(Adapter)類:一個轉換器,通過繼承或引用適配者的對象,把適配者接口轉換成目標接口,讓客戶按目標接口的格式訪問適配者。
適配器模式分為:
-
類適配器
-
對象適配器
兩者的區別在于:適配器與適配者的關系。類適配器是繼承關系,對象適配器是聚合關系。根據設計原則,聚合優先于繼承,應多選用對象適配器。
1.3 代碼示例
// 目標接口
public interface Target {void request();
}// 適配者類
public class Adaptee {public void specificRequest() {System.out.println("適配者中的業務代碼被調用!");}
}// 類適配器
public class ClassAdapter extends Adaptee implements Target {@Overridepublic void request() {this.specificRequest();}
}// 對象適配器
public class ObjectAdapter implements Target {private Adaptee adaptee;public ObjectAdapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {this.adaptee.specificRequest();}
}// 測試代碼
public class Client {public static void main(String[] args) {Target classAdapter = new ClassAdapter();classAdapter.request();Target objectAdapter = new ObjectAdapter(new Adaptee());objectAdapter.request();}
}
2. 適配器模式在實際開發中的應用
2.1 需求描述
為了提升系統的速度,將一些數據以 K-V 形式緩存在內存中,平臺提供 get、put、remove 等 API 以及相關的管理機制。
功能實現的迭代過程,從 HashMap 到 Memcached 再到 Redis,要確保后面再增加新的緩存組件時,能夠實現自由的切換,并且還要符合開閉原則。
設計問題:
- 如何在符合開閉原則前提下,實現功能的擴展?
- 兩種客戶端 API 不相同,如何保證自由切換?
使用適配器模式。
2.2 功能實現
使用適配器模式將功能相似的多種第三方組件(實現方案),統一成自己需要的 API,業務代碼只依賴已經統一的 API,而不依賴第三方 API。
(1) 定義一個緩存接口,包含 get、put、remove 等操作方法。例如:
public interface Cache {void put(String key, Object value);Object get(String key);void remove(String key);
}
(2) 實現該接口的三個適配器,分別對應 HashMap、Memcached、Redis 三種緩存方案。例如:
// HashMap 適配器
public class HashMapCacheAdapter implements Cache {private Map<String, Object> cache = new HashMap<>();@Overridepublic void put(String key, Object value) {cache.put(key, value);}@Overridepublic Object get(String key) {return cache.get(key);}@Overridepublic void remove(String key) {cache.remove(key);}
}// Memcached 適配器
public class MemcachedCacheAdapter implements Cache {private MemcachedClient memcachedClient;public MemcachedCacheAdapter(MemcachedClient memcachedClient) {this.memcachedClient = memcachedClient;}@Overridepublic void put(String key, Object value) {memcachedClient.set(key, 0, value);}@Overridepublic Object get(String key) {return memcachedClient.get(key);}@Overridepublic void remove(String key) {memcachedClient.delete(key);}
}// Redis 適配器
public class RedisCacheAdapter implements Cache {private Jedis jedis;public RedisCacheAdapter(Jedis jedis) {this.jedis = jedis;}@Overridepublic void put(String key, Object value) {jedis.set(key, value.toString());}@Overridepublic Object get(String key) {return jedis.get(key);}@Overridepublic void remove(String key) {jedis.del(key);}
}
(3) 創建工廠類,根據配置文件中的配置來創建相應的緩存適配器。例如:
public class CacheAdapterFactory {public static Cache createCacheAdapter(String type) {if ("HashMap".equals(type)) {return new HashMapCacheAdapter();} else if ("Memcached".equals(type)) {MemCachedClient memCachedClient = new MemCachedClient();return new MemcachedCacheAdapter(memCachedClient);} else if ("Redis".equals(type)) {Jedis jedis = new Jedis("localhost", 6379);return new RedisCacheAdapter(jedis);} else {throw new IllegalArgumentException("Invalid cache type: " + type);}}
}
使用時,只需要調用工廠類的 createCacheAdapter
方法,傳入緩存類型即可獲取相應的緩存適配器。例如:
public class Client {public static void main(String[] args) {Cache cache = CacheAdapterFactory.createCacheAdapter("Redis");cache.put("key", "value");Object result = cache.get("key");cache.remove("key");}
}
3. 適配器模式總結
優點:
- 解耦合: 適配器模式允許兩個沒有直接關聯的類協同工作,降低了它們之間的耦合度。
- 提高復用性: 通過適配器,可以重用現有的類,而不需要修改它們的代碼。
- 統一接口: 適配器模式提供了一種方法來統一多個不同的接口,使得它們可以被統一對待。
- 隱藏實現: 適配器模式隱藏了現有類的實現細節,只暴露出需要的接口。
- 靈活性: 可以根據需要自由地適配不同的類,提供了高度的靈活性。
缺點:
- 單一適配限制: 使用類適配器時,一次最多只能適配一個適配者類,這可能限制了其應用范圍。
- 系統復雜度: 如果過度使用適配器,可能會導致系統結構變得復雜,難以理解和維護。
適用場景:
- 接口統一: 當需要統一多個類的接口時,適配器模式可以有效地將它們適配到一個統一的接口。
- 兼容性需求: 當現有的接口無法修改,但需要與其他系統或模塊兼容時,適配器模式可以提供解決方案。