適配器模式
基本概念
-
適配器:
就是使得一個東西適合另外一個東西的東西。 -
定義:
適配器模式(Adapter),將一個類的接口轉換成客戶希望的另外一個接口。Adapter
模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。簡單地概括,就是需要的東西在眼前,但是不能使用,短時間又無法改造它,於是我們就通過適配器來適配它適合我們使用。 -
分類:
- 類適配器模式: 通過
多重繼承
對一個接口與另外一個接口進行匹配。 - 對象適配器模式:
由於Java/C#/VB.NET
語言,只支持了類的單繼承(C++
可支持類的多繼承),所以下面的都是主講對象適配器。
基本結構和代碼
UML圖
實現代碼
Target
客戶所期待的接口(可以是具體/抽象類或接口)
/**
* @create on 2020/6/14 14:13
* @description 目標類,這是客戶所期待的接口或(具體/抽象)類。
* @author mrdonkey
*/
open class Target {
open fun request() {
println("普通請求!")
}
}
Adaptee
需要適配的類
/**
* @create on 2020/6/14 14:16
* @description 需要是適配的類
* @author mrdonkey
*/
class Adaptee {
fun specificRequest(){
println("特殊請求!")
}
}
Adapter
適配器類
/**
* @create on 2020/6/14 14:16
* @description 適配器類(目標類的實現類),通過在內部包裝一個需要適配的類Adaptee對象 ,把源接口轉成目標接口。
* 簡單的來說,就是當目標類調用指定的方法時,內部實現執行適配的方法,達到適配的效果。
* @author mrdonkey
*/
class Adapter : Target() {
private val adaptee = Adaptee()//建立一個私有的Adaptee對象
override fun request() {
adaptee.specificRequest()//表面是Target的request方法,實際變成調用了想要適配的類的方法。
}
}
Client
客戶端
/**
* @create on 2020/6/14 14:19
* @description 客戶端測試
* @author mrdonkey
*/
class Client {
companion object {
@JvmStatic
fun main(args: Array<String>) {
val target = Adapter()
target.request()//達到adaptee能適合Target使用的效果。
}
}
}
測試結果:
特殊請求!
何時應用
- 希望複用一些現存的一些類,但是接口又和複用環境不一致的情況。
- 兩個類所做的事情相似,但是具備不同接口,首先考慮通過重構統一接口;若是雙方都是不太容易修改的再使用適配器模式適配,而不是一有不同時就使用。
- 進行設計前預防接口不同問題發生;在有小的接口不統一時,及時重構;碰到無法改變原有的設計和代碼的情況,才考慮使用適配器適配。
NBA小案例
-
設計一場簡單的球賽有前峯、中鋒、後衛,他們都有一個action行爲接收英文命令command。
-
UML圖
Player
球員抽象類
/**
* @create on 2020/6/14 14:24
* @description 抽象球員類
* @author mrdonkey
*/
abstract class Player {
/**
* 擁有一個接受命令而行動的方法
*/
abstract fun action(command: String)
}
Forwards
前鋒
/**
* @create on 2020/6/14 14:27
* @description 前鋒
* @author mrdonkey
*/
class Forwards : Player() {
override fun action(command: String) {
println("${this.javaClass.simpleName}----->$command")
}
}
Center
中鋒和Guards
後衛類似。
Client
賽場
/**
* @create on 2020/6/14 14:30
* @description 球場
* @author mrdonkey
*/
class Client {
companion object {
@JvmStatic
fun main(args: Array<String>) {
val forwards = Forwards()
forwards.action("attack")//收到進攻命令
val center = Center()
center.action("attack")
val guards = Center()
guards.action("defense")//收到防守命令
}
}
}
測試結果:
Forwards----->attack
Center----->attack
Center----->defense
-
假如在這場比賽中加入一個只會中文的中國中鋒球員
ChinaCenter
,他聽不懂英語也就無法通過接受英文的command進行行動,爲了適配ChinaCenter這個類
,我們需要創建一個翻譯者Translator
來適配,讓ChinaCenter能夠加入到球賽中。 -
應用適配器模式的UML圖
ChinaCenter
中國中鋒球員類
爲什麼他不繼承於Player
類?我們在這裏假設中國中鋒這類是無法輕易更改的,即便繼承於它,由於中鋒球員是無法聽懂英語command的,那就沒辦法進行比賽了,所以需要一個翻譯者來進行翻譯(適配),讓它也能夠加入賽場,這個例子不夠嚴謹,僅是爲了演示適配器模式的一種應用
。
/**
* @create on 2020/6/14 14:35
* @description 中國中鋒球員 只會中文
* @author mrdonkey
*/
class ChinaCenter {
fun action(command: String) {
println("${this.javaClass.simpleName}----->$command")
}
}
Translator
翻譯者 作爲ChinaCenter
的適配器
/**
* @create on 2020/6/14 14:33
* @description 翻譯者(中國球員的適配器,讓中國球員能夠聽得懂) 爲中國球員提供翻譯
* @author mrdonkey
*/
class Translator : Player() {
private val chinaCenter = ChinaCenter()//表明翻譯者與中國中鋒球員有關聯
/**
* s
*/
override fun action(command: String) {
chinaCenter.action(//告訴中國中鋒
when (command) {
"attack" -> {//翻譯進攻
"進攻"
}
"defense" -> {//翻譯防守
"防守"
}
else -> {
""
}
}
)
}
}
中國中鋒加入球賽
Client
賽場
class Client {
companion object {
@JvmStatic
fun main(args: Array<String>) {
//...省略
val chinaPlayer = Translator()
chinaPlayer.action("attack")
}
}
}
測試結果:
ChinaCenter----->進攻