網(wǎng)站技術(shù)介紹聊城網(wǎng)站推廣公司
設(shè)計模式大賞(一):橋接模式,組合模式
導(dǎo)言
本篇文章是設(shè)計模式大賞中的第一篇文章,這個系列的文章中我們主要將介紹一些常見的設(shè)計模式,主要是我在看Android源碼中發(fā)現(xiàn)用到的一些設(shè)計模式。本篇文章將主要介紹橋接模式 和
組合模式 這兩種設(shè)計模式。
本篇文章主要參考:《大話設(shè)計模式》
橋接模式
Android中的橋接模式
我一開始接觸到橋接模式是在學習Android的WindowManager相關(guān)的源碼過程中,具體來說,WindowManager
的實現(xiàn)類WindowManagerImpl
實際上并不直接實現(xiàn)相關(guān)的請求,而是將其委托給WindowManagerGlobal
這個單例類來實現(xiàn)。這樣將實現(xiàn)分為抽象和具體兩部分的模式就叫做橋接模式。
合成/聚合復(fù)用原則
在正式介紹到橋接模式之前我們需要先介紹一下合成聚合復(fù)用原則,該原則的核心思想就是:盡量使用合成和聚合,而不要
去使用類的繼承。
聚合表示一種弱的擁有關(guān)系
,即A對象可以包含B對象,但B對象不是A對象的一部分。比如說整個班級中可以包含我們個人,但是我們個人并不是班級的一部分,我們脫離開班級還是可以獨立存在的,班級脫離我們也可以獨立存在。
合成則表示一種強的擁有關(guān)系
,比如說雞翅對于雞一樣,顯然雞翅是雞的一部分,他們的生命周期是一致的,誰也脫離不開誰。
但無論是聚合還是合成關(guān)系,他們的耦合強度都要低于繼承,繼承是一種強耦合的關(guān)系,遵循合成/聚合復(fù)用原則可以防止類發(fā)展成一個難以管理的龐然大物。
橋接模式的概念
橋接模式(Bridge),是一種將抽象部分與它的實現(xiàn)部分分離,使他們都可以獨立變化的一種設(shè)計模式。
下面是一個標準的橋接模式的基本模板:
實際上這樣說還是很抽象,我們可以借用大話設(shè)計模式中的例子來說明:
比如說對手機來說,我們可以將其拆分出兩個抽象的概念:手機的硬件和手機的軟件,對于我們Android端來說,各個手機廠商的硬件之間都是高度定制化的,所以我們可以將其簡化為手機廠商的品牌和手機的軟件這兩個抽象:
顯然各個品牌手機的手機都會持有各自的手機軟件,但是手機軟件并不是屬于手機的一部分,這是一種聚合持有的關(guān)系。這樣分類的原因就是為了方便手機品牌和手機軟件之間各自的拓展:即為每個抽象添加功能不涉及到其他類的修改。
實際上,我覺得橋接模式強調(diào)的就一點:通過多個角度將一個系統(tǒng)進行切分,使各個部分在變化的時候不影響其他部分的變化。
這樣做的好處有:
- 使系統(tǒng)更加靈活,能夠獨立地擴展和變化抽象部分和實現(xiàn)部分。
- 提高了系統(tǒng)的可維護性和可擴展性,因為可以通過添加新的抽象或?qū)崿F(xiàn)類來擴展系統(tǒng)。
橋接模式的具體示例
為了更好地理解,接下來引入一個具體的實例:比如說我們想要生產(chǎn)瓶裝飲料的話,就可以將這整個罐裝飲料抽象成兩個部分:裝飲料的瓶子和具體的飲料
下面是我的示例代碼:
fun main() {val Glass:Bottle = GlassBottle(Cola())val Plastic:Bottle = PlasticBottle(Sprite())val Bridge = BottleBridgeImpl()Bridge.LoadDrink(Glass)Bridge.LoadDrink(Plastic)
}
//抽象類-瓶子
abstract class Bottle(var mDrinks:Drinks) {//制作瓶子的方法abstract fun MakeBottle()}
//抽象類-飲料
abstract class Drinks{//生產(chǎn)飲料的方法abstract fun MakeDrinks()
}
//抽象出連接上面兩個抽象類的橋接方法
interface BottleBridge{//裝瓶的方法fun LoadDrink(bottle:Bottle)
}class BottleBridgeImpl():BottleBridge{override fun LoadDrink(bottle: Bottle) {println("壓縮裝瓶,倒入${bottle.mDrinks}")}
}class GlassBottle(mDrinks: Drinks):Bottle(mDrinks) {override fun MakeBottle() {println("生產(chǎn)玻璃瓶")}
}class PlasticBottle(mDrinks: Drinks):Bottle(mDrinks) {override fun MakeBottle() {println("生產(chǎn)塑料瓶")}
}class Cola():Drinks(){override fun MakeDrinks() {println("生產(chǎn)可樂")}override fun toString(): String {return "可樂"}
}class Sprite():Drinks() {override fun MakeDrinks() {println("生產(chǎn)雪碧")}override fun toString(): String {return "雪碧"}
}
此處我將飲料和瓶子這兩部分抽象出來,并引入了一個連接這兩個部分的橋接接口,這樣飲料和瓶子這兩個抽象概念在變化的過程只需要維護自身的制造方法即可而不需要關(guān)注其他部分。
總而言之,我覺得橋接模式的核心就是從多個維度將一個系統(tǒng)進行拆分,抽象出各個抽象部分,然后各個抽象部分各自有自己的實現(xiàn),使得一個抽象部分的具體實現(xiàn)變化時不影響其他的部分。
組合模式
組合模式的概念
組合模式,是將對象組合成樹形結(jié)構(gòu)以表示
整體-部分
的層次結(jié)構(gòu)。組合模式使得用戶對單個對象和組合對象的使用具有一致性。
這整個描述里有兩個關(guān)鍵字:樹形結(jié)構(gòu)以及一致性。這里我們可以以一個學校的管理為例,學校的管理系統(tǒng)首先是一個大的全局的學校管理系統(tǒng),向下細分又可以分為學院管理系統(tǒng),再向下還可以分為各個專業(yè)的管理系統(tǒng),這整個結(jié)構(gòu)是一個樹形的結(jié)構(gòu);而對于各個層級的管理系統(tǒng)我們肯定希望他們對具體信息的操作是一致的,比如說我們可以在學院管理系統(tǒng)對學生A進行加分操作,也可以在專業(yè)管理系統(tǒng)中對學生A進行加分操作,這個加分操作無論是在哪個層級的管理系統(tǒng)中發(fā)起的都應(yīng)該有一致的效果,這就是一致性。
下面是組合模式的典型結(jié)構(gòu)圖:
Android中的組合模式
說到這里是不是覺得這個組合模式很像Android中ViewGroup和View的組合關(guān)系,實際上確實如此,通過使用組合模式,Android開發(fā)人員可以更容易地管理和操作UI元素,以便以可擴展和靈活的方式構(gòu)建用戶界面。每個 ViewGroup 作為容器可以包含多個子 View,從而形成了整個布局的層次結(jié)構(gòu)。
何時使用組合模式
使用組合模式的最佳場景就是當你發(fā)現(xiàn)需求中體現(xiàn)的是整體與部分層次的結(jié)構(gòu)時,以及你希望用戶可以忽略組合對象與單個對象的不同,統(tǒng)一的使用組合結(jié)構(gòu)中的所有對象時,此時就應(yīng)該考慮使用組合模式了,在上面說到了Android整個視圖層次就是用到了組合模式,實際上Java上的UI層次也類似。
這個組合模式如果理解了Android中View的視圖層次應(yīng)該就很形象了,此處就不再另加例子,大家可以去看看Android中View的視圖層次。
使用組合模式的好處
使用組合模式的好處,首先我覺得如果體現(xiàn)的是整體與部分的層次結(jié)構(gòu)時,使用組合模式顯然可以讓整個需求的層次更加清晰。
其次,用戶不用關(guān)心這到底是一個組件組還是一個組件,簡單來說組合模式讓用戶可以一致地使用組合結(jié)構(gòu)和單個對象。