前言
關(guān)于面向?qū)ο蟮牧笤瓌t請(qǐng)參考前面的博文
csdn上關(guān)于23種設(shè)計(jì)模式的專(zhuān)題
http://blog.csdn.net/column/details/pattern.html
單例模式
public class Singleton{
//volatile 關(guān)鍵字保證Singleton實(shí)例在內(nèi)存總是最新的
private volatile static Singleton instance;
//將默認(rèn)的構(gòu)造函數(shù)私有化,防止其他類(lèi)手動(dòng)new
private Singleton(){};
//獲取Singleton實(shí)例的唯一方式
public static Singleton getInstance(){
if(instance==null){
sychronized(Singleton.class){
if(instance==null)
instance=new Singleton();
}
}
return instatnce;
}
}
單例模式看起來(lái)簡(jiǎn)單惫皱,但其實(shí)還有幾個(gè)地方需要注意的
1、volatile關(guān)鍵字的作用是:線程每次使用到被volatile關(guān)鍵字修飾的變量時(shí),都會(huì)去堆里拿最新的數(shù)據(jù)。當(dāng)一個(gè)線程在執(zhí)行instance=new Singleton()時(shí)战坤,其實(shí)執(zhí)行了三個(gè)指令
1衰猛、給Singleton實(shí)例分配內(nèi)存
2、調(diào)用Singleton()構(gòu)造函數(shù)向图,初始化成員字段
3、將instance對(duì)象指向分配的內(nèi)存(此時(shí)instance就不是null啦~)
在jvm執(zhí)行指令的時(shí)候2标沪、3的順序是不確定的榄攀,也就是jvm有可能先初始化Singleton實(shí)例,然后再把實(shí)例只想分配的內(nèi)存地址金句,或者先把實(shí)例指向內(nèi)存地址在對(duì)實(shí)例進(jìn)行初始化檩赢。考慮這樣一種情況:一開(kāi)始违寞,第一個(gè)線程執(zhí)行instance=new Singleton();這句時(shí)贞瞒,JVM先指向一個(gè)堆地址,而此時(shí)趁曼,又來(lái)了一個(gè)線程2军浆,它發(fā)現(xiàn)instance不是null,就直接拿去用了挡闰,但是堆里面對(duì)單例對(duì)象的初始化并沒(méi)有完成乒融,最終出現(xiàn)錯(cuò)誤。
2、第一次空指針判斷簇抵,這個(gè)比較好理解庆杜,為了防止實(shí)例已創(chuàng)建的情況下,避免多線程的不必要的同步阻塞碟摆。
3晃财、第二次空指針判斷,主要考慮這樣一種情況:當(dāng)有2個(gè)線程同時(shí)到達(dá)了sychronized{}處(當(dāng)并發(fā)量很大的時(shí)候這種情況是存在的)典蜕,其中一個(gè)線程拿到了 Singleton類(lèi)鎖(區(qū)別對(duì)象鎖和類(lèi)鎖)断盛,進(jìn)入了sychronized{}里面執(zhí)行完了對(duì)象初始化并釋放了類(lèi)鎖,同時(shí)由于第二個(gè)線程已經(jīng)跨過(guò)了第一次空指針判斷愉舔,所以它會(huì)拿到類(lèi)鎖進(jìn)入sychronized{}钢猛,此時(shí)的Singleton對(duì)象已經(jīng)被第一個(gè)線程初始化了不為空,第二個(gè)線程直接跳出同步塊轩缤,保證了單例的唯一性命迈。
Builer模式
public class MyBuilder{
private int id;
private String num;
public MyData build(){
MyData d=new MyData();
d.setId(id);
d.setNum(num);
return t;
}
public MyBuilder setId(int id){
this.id=id;
return this;
}
public MyBuilder setNum(String num){
this.num=num;
return this;
}
}
public class Test{
public static void main(String[] args){
MyData d=new MyBuilder().setId(10).setNum("hc").build();
}
}
Builer模式比較簡(jiǎn)單就不解釋了,當(dāng)一個(gè)對(duì)象初始化時(shí)所需的參數(shù)過(guò)多火的,又不全是必要參數(shù)時(shí)相當(dāng)有用壶愤,可以參考Android Dialog的創(chuàng)建,那里就使用了builder模式馏鹤。
原型模式
原型設(shè)計(jì)模式比較簡(jiǎn)單征椒,就是將一個(gè)對(duì)象進(jìn)行拷貝,但對(duì)象必須要實(shí)現(xiàn)Cloneable 接口湃累,像android中的View及其之類(lèi)就沒(méi)有實(shí)現(xiàn)Cloneable 不能進(jìn)行clone勃救。同時(shí)要區(qū)分原型模式和傳引用的區(qū)別。原型模式會(huì)創(chuàng)建一個(gè)新的對(duì)象治力,而傳引用只是新創(chuàng)建了一個(gè)引用但指向的是同一個(gè)對(duì)象蒙秒。同時(shí)原型模式又分為淺拷貝和深拷貝。
淺拷貝:就是拷貝了【基本數(shù)據(jù)類(lèi)型和引用類(lèi)型的引用】
深拷貝:【引用類(lèi)型內(nèi)的所有基本數(shù)據(jù)類(lèi)型的值】
參考:https://juejin.im/entry/593dee6c128fe1006aec7c3e
普通工廠模式
public abstract class Product{
public abstract void method();
}
public class ConcreteProductA extends Prodect{
public void method(){
System.out.println("我是產(chǎn)品A!");
}
}
public class ConcreteProductB extends Prodect{
public void method(){
System.out.println("我是產(chǎn)品B!");
}
}
public abstract class Factory{
public abstract Product createProduct();
}
public class MyFactory extends Factory{
public Product createProduct(){
return new ConcreteProductA();
}
}
其實(shí)普通工廠方法就是一種工廠生產(chǎn)一種產(chǎn)品琴许,工廠和產(chǎn)品都繼承對(duì)應(yīng)的抽象類(lèi)税肪。比較簡(jiǎn)單就不多分析了溉躲,大家自己看代碼把榜田。
抽象工廠模式
public abstract class AbstractProductA{
public abstract void method();
}
public abstract class AbstractProdectB{
public abstract void method();
}
public class ConcreteProductA1 extends AbstractProductA{
public void method(){
System.out.println("具體產(chǎn)品A1的方法!");
}
}
public class ConcreteProductA2 extends AbstractProductA{
public void method(){
System.out.println("具體產(chǎn)品A2的方法锻梳!");
}
}
public class ConcreteProductB1 extends AbstractProductB{
public void method(){
System.out.println("具體產(chǎn)品B1的方法箭券!");
}
}
public class ConcreteProductB2 extends AbstractProductB{
public void method(){
System.out.println("具體產(chǎn)品B2的方法!");
}
}
public abstract class AbstractFactory{
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}
public class ConcreteFactory1 extends AbstractFactory{
public AbstractProductA createProductA(){
return new ConcreteProductA1();
}
public AbstractProductB createProductB(){
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 extends AbstractFactory{
public AbstractProductA createProductA(){
return new ConcreteProductA2();
}
public AbstractProductB createProductB(){
return new ConcreteProductB2();
}
}
從代碼中可用看到疑枯,抽象工廠和普通工廠很相似辩块,唯一不同的是普通工廠每個(gè)工廠對(duì)應(yīng)只生產(chǎn)一種產(chǎn)品,而抽象工廠每個(gè)工廠會(huì)生產(chǎn)一組相關(guān)或者相互依賴(lài)的產(chǎn)品。
策略模式
策略模式從字面來(lái)理解其實(shí)就是一種編程策略(這不是廢話(huà)嗎废亭,說(shuō)跟沒(méi)說(shuō)一樣)国章,方便我們只要進(jìn)行簡(jiǎn)單的對(duì)象替換,就能實(shí)現(xiàn)功能相同豆村,但實(shí)現(xiàn)方式不同的算法液兽。幾個(gè)例子:我們現(xiàn)在要對(duì)數(shù)組進(jìn)行排序,我們有好多排序算法掌动,冒泡四啰,二分法,選擇等等粗恢。假如沒(méi)有采用策略模式柑晒,而是采用用編碼 我們有可能會(huì)這樣做(js 方便點(diǎn))
function executeSort(type){
if(type === "冒泡"){
....................
}else if(type === "二分法"){
.....................
}else if(type === "選擇"){
.....................
}
.......................
}
executeSort("冒泡")
executeSort("二分法")
executeSort("選擇")
貌似也還行,不算分復(fù)雜嗎眷射,但是這個(gè)的前提我們事先已經(jīng)定義好了這幾種算法匙赞,可是萬(wàn)一有一天,我們發(fā)現(xiàn)現(xiàn)有的算法滿(mǎn)足不了我們的需求妖碉,我們要新增一種排序算法罚屋,加入就叫"史上最快排序"算法,我們?cè)趺崔k嗅绸,我們要新增
else if(type === "史上最快排序"){
.....................
}
executeSort("史上最快排序")
也還好脾猛,改的不多,然后產(chǎn)品所我們要新增"史上最快排序1"~"史上最快排序9"鱼鸠,我估計(jì)你會(huì)看著一大串的 else if想要爆粗口吧猛拴,最后戀看都不想看一下代碼。好的蚀狰,讓我們換一種方式來(lái)實(shí)現(xiàn):
interface AbstractSort{
void sort();
}
class 史上最快排序1 implements AbstractSort{
void sort(){
}
}
.......
class 史上最快排序9 implements AbstractSort{
void sort(){
}
}
void executeSort(AbstractSort sort){
sort.sort()
}
executeSort(new 史上最快排序1() )
要新增的時(shí)候我們只需要新增一個(gè)類(lèi)并修改一行代碼就夠了愉昆,每個(gè)類(lèi)實(shí)現(xiàn)自己的算法,多么清晰麻蹋。
狀態(tài)模式
狀態(tài)模式和策略模式在編碼方式上很像跛溉,但是要表達(dá)東西和概念卻不一樣。
狀態(tài)模式中扮授,行為是有狀態(tài)來(lái)決定的芳室,不同的狀態(tài)下會(huì)執(zhí)行不同的行為。舉個(gè)例子把刹勃,比如電視堪侯,電視有2個(gè)狀態(tài),一個(gè)是開(kāi)機(jī)荔仁,一個(gè)是關(guān)機(jī)伍宦,開(kāi)機(jī)時(shí)可以切換頻道芽死,關(guān)機(jī)時(shí)切換頻道不做任何響應(yīng)。
策略模式:每個(gè)模式是相互獨(dú)立的次洼,可以相互替換关贵,得到的結(jié)果是一樣的,只是實(shí)現(xiàn)方式不同
狀態(tài)模式:平行的不可替換的卖毁,因?yàn)槊糠N狀態(tài)下表現(xiàn)出來(lái)的行為是不一樣的坪哄。
責(zé)任鏈模式
多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接受者直接的耦合關(guān)系势篡,將這些對(duì)象連成一條鏈翩肌,并沿這條鏈傳遞該請(qǐng)求,直到有對(duì)象處理它為止禁悠。
幾個(gè)例子念祭,Android中的view事件傳遞就用到了責(zé)任鏈模式,最外層的Activity首先捕獲到了觸摸事件碍侦,如果自己不處理粱坤,則將事件傳遞給子view處理,一直到有view處理為止(其實(shí)這跟js中的原型鏈有點(diǎn)像瓷产,感興趣的朋友可以去了解一下)站玄。這里就不貼代碼了,大家可以去看下Android事件傳遞的源碼濒旦。里面涉及到好多設(shè)計(jì)模式(最主要的是策略+責(zé)任鏈)株旷。
解釋器模式
概念:給定一個(gè)語(yǔ)言,定義它的語(yǔ)法尔邓,并定義一個(gè)解釋器晾剖,這個(gè)解釋器用于解析語(yǔ)言。
舉個(gè)例子梯嗽,比如我們?cè)趚ml中定義的布局如何轉(zhuǎn)化成我們常見(jiàn)的對(duì)象齿尽,這其實(shí)就用到了解釋器模式。解釋器模式的側(cè)重點(diǎn)在于解析灯节。
適配器模式
概念:把一個(gè)類(lèi)的接口變換成客戶(hù)端所期待的另一個(gè)接口循头,從而使原本因接口不匹配而無(wú)法在一起工作的兩個(gè)類(lèi)能夠在一起工作。
舉個(gè)最簡(jiǎn)單的例子: 比較典型的有ListView和RecyclerView炎疆,其實(shí)適配器模式就是把2中不相關(guān)的對(duì)象連接在一起了卡骂,因?yàn)閘istview其實(shí)只關(guān)心itemview,不關(guān)心data磷雇,那怎樣將數(shù)據(jù)展現(xiàn)在listview里呢偿警,這里就用到了adapter。其實(shí)適配器模式的作用就是適配和連接唯笙。我們生活中的電源線插頭其實(shí)就是一種適配器模式螟蒸。插頭將我們的各種電器和插口連接起來(lái),每種電器都有可能有不同的接口崩掘,但是電源線將這種連接給屏蔽掉了七嫌。仔細(xì)觀察,生活當(dāng)中處處都是知識(shí)點(diǎn)啊苞慢。
命令模式
舉個(gè)生活中的日子:我點(diǎn)擊電腦的關(guān)機(jī)鍵诵原,我們就會(huì)得到一個(gè)關(guān)機(jī)的最終結(jié)果,那至于在電腦處于關(guān)機(jī)狀態(tài)之前發(fā)生了什么(保存數(shù)據(jù)挽放,結(jié)束進(jìn)程绍赛,切斷電源等等),不需要我們關(guān)心辑畦。
所以簡(jiǎn)單來(lái)講就是將一系列相關(guān)的動(dòng)作封裝在一起吗蚌,提供給調(diào)用者一個(gè)統(tǒng)一的接口,通過(guò)調(diào)用不同的參數(shù)纯出,最終展現(xiàn)出基于參數(shù)的唯一結(jié)果(感覺(jué)有點(diǎn)類(lèi)似函數(shù)式編程中的純函數(shù)概念)蚯妇。
觀察者模式
觀察者模式我們平時(shí)用得比較多,存在1對(duì)n的概念暂筝,當(dāng)1發(fā)生變化時(shí)箩言,所有的n都會(huì)接收到通知,比如rxjava就是充分展現(xiàn)了觀察者模式的精髓焕襟,大家有時(shí)間可以去看下相關(guān)源碼陨收,里面有三個(gè)主要的角色:觀察者、被觀察者鸵赖、訂閱畏吓,當(dāng)訂閱關(guān)系發(fā)生時(shí),觀察者就能接收到被觀察所觸發(fā)的行為卫漫。
備忘錄模式(參考網(wǎng)上的定義)
備忘錄模式定義:在不破壞封閉的前提下菲饼,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在對(duì)象之外保存這個(gè)狀態(tài)列赎,這樣宏悦,以后就可將對(duì)象恢復(fù)到原先保存的狀態(tài)中。
其實(shí)就是相當(dāng)于一個(gè)提前備份包吝,一旦出現(xiàn)啥意外饼煞,能夠恢復(fù)。像我們平時(shí)用的word軟件诗越,意外關(guān)閉了砖瞧,它能幫我們恢復(fù)。其實(shí)就是它自動(dòng)幫我們備份過(guò)嚷狞。
那么Android哪里用到了備忘錄模式呢块促?Activity的onSaveInstanceState和onRestoreInstanceState就是用到了備忘錄模式荣堰,分別用于保存和恢復(fù)
迭代器模式(參考網(wǎng)上的定義)
迭代器模式定義:提供一種方法順序訪問(wèn)一個(gè)容器對(duì)象中的各個(gè)元素,而不需要暴露該對(duì)象的內(nèi)部表示竭翠。
相信熟悉Java的你肯定知道振坚,Java中就有迭代器Iterator類(lèi),本質(zhì)上說(shuō)斋扰,它就是用迭代器模式渡八。
按照慣例,看看Android中哪里用到了迭代器模式传货,Android源碼中屎鳍,最典型的就是Cursor用到了迭代器模式,當(dāng)我們使用SQLiteDatabase的query方法時(shí)问裕,返回的就是Cursor對(duì)象逮壁,通過(guò)如下方式去遍歷:
cursor.moveToFirst();
do{
//cursor.getXXX(int);
}while(cursor.moveToNext);
模板方法模式
模板方法其實(shí)在工作中用到得比較多,一般用于業(yè)務(wù)流程中僻澎,我們?cè)诔橄笾卸x執(zhí)行路口貌踏,提供給外部調(diào)用,然后把具體的實(shí)現(xiàn)方法通過(guò)繼承的方式讓之類(lèi)去實(shí)現(xiàn)窟勃。他們根本不需要去關(guān)心整體的業(yè)務(wù)流程祖乳,只需要去實(shí)現(xiàn)自己的具體方法就行了。
直接拿Android中的源碼來(lái)說(shuō)事秉氧!我們知道眷昆,啟動(dòng)一個(gè)Activity過(guò)程非常復(fù)雜,如果讓開(kāi)發(fā)者每次自己去調(diào)用啟動(dòng)Activity過(guò)程無(wú)疑是一場(chǎng)噩夢(mèng)汁咏。好在啟動(dòng)Activity大部分代碼時(shí)不同的亚斋,但是有很多地方需要開(kāi)發(fā)者定制。也就是說(shuō)攘滩,整體算法框架是相同的帅刊,但是將一些步驟延遲到子類(lèi)中,比如Activity的onCreate漂问、onStart等等赖瞒。這樣子類(lèi)不用改變整體啟動(dòng)Activity過(guò)程即可重定義某些具體的操作了~。
訪問(wèn)者模式
這種模式好像在實(shí)際開(kāi)發(fā)中運(yùn)用的并不多蚤假,以下文字網(wǎng)上博文栏饮。
定義:封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中各元素的操作,它可以在不改變這個(gè)數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作磷仰。
訪問(wèn)者模式是23種設(shè)計(jì)模式中最復(fù)雜的一個(gè)袍嬉,但他的使用率并不高,大部分情況下灶平,我們不需要使用訪問(wèn)者模式伺通,少數(shù)特定的場(chǎng)景才需要箍土。
Android中運(yùn)用訪問(wèn)者模式,其實(shí)主要是在編譯期注解中泵殴,編譯期注解核心原理依賴(lài)APT(Annotation Processing Tools)涮帘,著名的開(kāi)源庫(kù)比如ButterKnife拼苍、Dagger笑诅、Retrofit都是基于APT。
中介者模式
中介者模式感覺(jué)就像一個(gè)大管家疮鲫,在某一項(xiàng)具體的業(yè)務(wù)中吆你,全部都可以通過(guò)他來(lái)完成,而不需要對(duì)接這個(gè)模塊中的其他對(duì)象俊犯「径啵看看生活中的房產(chǎn)中介應(yīng)該就比較好理解了,他連接了買(mǎi)方和賣(mài)方燕侠,而這2種角色卻可以不用直接對(duì)接者祖。用另一句話(huà)來(lái)說(shuō)就是專(zhuān)業(yè)的人做專(zhuān)業(yè)的事,當(dāng)然不同的對(duì)象就要負(fù)責(zé)自己擅長(zhǎng)的事绢彤。
我們知道系統(tǒng)啟動(dòng)時(shí)七问,各種系統(tǒng)服務(wù)會(huì)向ServiceManager提交注冊(cè),即ServiceManager持有各種系統(tǒng)服務(wù)的引用 茫舶,當(dāng)我們需要獲取系統(tǒng)的Service時(shí)械巡,比如ActivityManager、WindowManager等(它們都是Binder)饶氏,首先是向ServiceManager查詢(xún)指定標(biāo)示符對(duì)應(yīng)的Binder讥耗,再由ServiceManager返回Binder的引用。并且客戶(hù)端和服務(wù)端之間的通信是通過(guò)Binder驅(qū)動(dòng)來(lái)實(shí)現(xiàn)疹启,這里的ServiceManager和Binder驅(qū)動(dòng)就是中介者
代理模式&裝飾模式
裝飾器模式關(guān)注于在一個(gè)對(duì)象上動(dòng)態(tài)的添加方法古程,然而代理模式關(guān)注于控制對(duì)對(duì)象的訪問(wèn)。換句話(huà) 說(shuō)喊崖,用代理模式挣磨,代理類(lèi)(proxy class)可以對(duì)它的客戶(hù)隱藏一個(gè)對(duì)象的具體信息〈恚可能還算比較模糊趋急,用網(wǎng)上的2中uml圖來(lái)理解一下。
代理模式:
裝飾者模式
從圖中我們可以看到2總模式非常類(lèi)似势誊,唯一不同的是在代理模式中呜达,代理類(lèi)似直接持有被代理對(duì)象的,而在調(diào)用時(shí)也是直接創(chuàng)建的代理類(lèi)粟耻,初始化代理類(lèi)的同時(shí)也初始化了被代理類(lèi)查近。而裝飾著模式中眉踱,裝飾類(lèi)和被裝飾類(lèi)往往不存在直接的引用,裝飾類(lèi)持有雙方共同的抽象類(lèi)霜威,在調(diào)用的時(shí)候通過(guò)構(gòu)造函數(shù)傳入谈喳。
總結(jié)
1、從語(yǔ)意上講戈泼,代理模式是為控制對(duì)被代理對(duì)象的訪問(wèn)婿禽,而裝飾模式是為了增加被裝飾對(duì)象的功能
2、代理類(lèi)所能代理的類(lèi)完全由代理類(lèi)確定大猛,裝飾類(lèi)裝飾的對(duì)象需要根據(jù)實(shí)際使用時(shí)客戶(hù)端的組合來(lái)確定
3扭倾、被代理對(duì)象由代理對(duì)象創(chuàng)建,客戶(hù)端甚至不需要知道被代理類(lèi)的存在挽绩;被裝飾對(duì)象由客戶(hù)端創(chuàng)建并傳給裝飾對(duì)象
組合模式
例子:對(duì)于一家大型公司膛壹,每當(dāng)公司高層有重要事項(xiàng)需要通知到總部每個(gè)部門(mén)以及分公司的各個(gè)部門(mén)時(shí),并不希望逐一通知唉堪,而只希望通過(guò)總部各部門(mén)及分公司模聋,再由分公司通知其所有部門(mén)。這樣唠亚,對(duì)于總公司而言链方,不需要關(guān)心通知的是總部的部門(mén)還是分公司
很簡(jiǎn)單 直接上uml圖
享元模式(來(lái)自于網(wǎng)絡(luò))
定義:使用享元對(duì)象有效地支持大量的細(xì)粒度對(duì)象。
享元模式我們平時(shí)接觸真的很多趾撵,比如Java中的常量池侄柔,線程池等。主要是為了重用對(duì)象占调。
在Android哪里用到了享元模式呢暂题?線程通信中的Message,每次我們獲取Message時(shí)調(diào)用Message.obtain()其實(shí)就是從消息池中取出可重復(fù)使用的消息究珊,避免產(chǎn)生大量的Message對(duì)象薪者。
外觀模式
定義:要求一個(gè)子系統(tǒng)的外部與其內(nèi)部的通信必須通過(guò)一個(gè)統(tǒng)一的對(duì)象進(jìn)行。
怎么理解呢剿涮,舉個(gè)例子言津,我們?cè)趩?dòng)計(jì)算機(jī)時(shí),只需按一下開(kāi)關(guān)鍵取试,無(wú)需關(guān)系里面的磁盤(pán)悬槽、內(nèi)存、cpu瞬浓、電源等等這些如何工作初婆,我們只關(guān)心他們幫我啟動(dòng)好了就行。實(shí)際上,由于里面的線路太復(fù)雜磅叛,我們也沒(méi)辦法去具體了解內(nèi)部電路如何工作屑咳。主機(jī)提供唯一一個(gè)接口“開(kāi)關(guān)鍵”給用戶(hù)就好。
那么Android哪里使用到了外觀模式呢弊琴?依然回到Context兆龙,Android內(nèi)部有很多復(fù)雜的功能比如startActivty、sendBroadcast敲董、bindService等等紫皇,這些功能內(nèi)部的實(shí)現(xiàn)非常復(fù)雜,如果你看了源碼你就能感受得到臣缀,但是我們無(wú)需關(guān)心它內(nèi)部實(shí)現(xiàn)了什么坝橡,我們只關(guān)心它幫我們啟動(dòng)Activity泻帮,幫我們發(fā)送了一條廣播精置,綁定了Activity等等就夠了。
橋接模式
橋接模式(Bridge Pattern)锣杂,將抽象部分與它的實(shí)現(xiàn)部分分離脂倦,使它們都可以獨(dú)立地變化。更容易理解的表述是:實(shí)現(xiàn)系統(tǒng)可從多種維度分類(lèi)元莫,橋接模式將各維度抽象出來(lái)赖阻,各維度獨(dú)立變化,之后可通過(guò)聚合踱蠢,將各維度組合起來(lái)火欧,減少了各維度間的耦合。
對(duì)比一下一下2張圖
不必要的繼承導(dǎo)致類(lèi)爆炸
從上圖可以看到茎截,對(duì)于每種組合都需要?jiǎng)?chuàng)建一個(gè)具體類(lèi)苇侵,如果有N個(gè)維度,每個(gè)維度有M種變化企锌,則需要MNMN個(gè)具體類(lèi)榆浓,類(lèi)非常多,并且非常多的重復(fù)功能撕攒。
如果某一維度陡鹃,如Transmission多一種可能,比如手自一體檔(AMT)抖坪,則需要增加3個(gè)類(lèi)萍鲸,BMWAMT,BenZAMT擦俐,LandRoverAMT脊阴。
橋接模式類(lèi)圖
從上圖可知,當(dāng)把每個(gè)維度拆分開(kāi)來(lái),只需要M*N個(gè)類(lèi)蹬叭,并且由于每個(gè)維度獨(dú)立變化藕咏,基本不會(huì)出現(xiàn)重復(fù)代碼。
此時(shí)如果增加手自一體檔秽五,只需要增加一個(gè)AMT類(lèi)即可