15 Bridge Pattern(橋接模式)
前言:把實現(xiàn)分開,讓它們各自變化
需求:
麥當(dāng)當(dāng)和肯打基是Vander小時候的最愛,Vander發(fā)達(dá)之后,他也想加盟它們?nèi)シ忠槐F(xiàn)在合同已經(jīng)談攏了,Vander開始加盟它們制作食物,他很快就開始了設(shè)計,設(shè)計如下:
Restaurant:
public abstract class Restaurant {
protected abstract void makeFood();
}
Kentucky:
public abstract class Kentucky extends Restaurant {
}
MacDonald:
public abstract class MacDonald extends Restaurant {
}
KentuckyFriedChickenFactory:
public class KentuckyFriedChickenFactory extends Kentucky {
// 獲取父類的名字(super.getClass().getSimpleName()依然還是獲取當(dāng)前類的名字)
private final String RESTAURANT_NAME = this.getClass().getSuperclass().getSimpleName();
public void makeFood() {
System.out.println("生產(chǎn)" + RESTAURANT_NAME + "的炸雞");
}
}
MacDonaldFriedChickenFactory:
public class MacDonaldFriedChickenFactory extends MacDonald {
private final String RESTAURANT_NAME = super.getClass().getSuperclass().getSimpleName();
public void makeFood() {
System.out.println("生產(chǎn)" + RESTAURANT_NAME + "的炸雞");
}
}
KentuckyHamburgFactory:
public class KentuckyHamburgFactory extends Kentucky {
private final String RESTAURANT_NAME = this.getClass().getSuperclass().getSimpleName();
public void makeFood() {
System.out.println("生產(chǎn)" + RESTAURANT_NAME + "的漢堡");
}
}
MacDonaldHamburgFactory:
public class MacDonaldHamburgFactory extends MacDonald {
private final String RESTAURANT_NAME = this.getClass().getSuperclass().getSimpleName();
public void makeFood() {
System.out.println("生產(chǎn)" + RESTAURANT_NAME + "的炸雞");
}
}
首先肯打雞跟麥當(dāng)當(dāng)都是Restaurant,很理所當(dāng)然地實現(xiàn)Restaurant接口,肯打雞生產(chǎn)漢堡的工廠跟生產(chǎn)炸雞的工廠都繼承Kentucky,類似的麥當(dāng)當(dāng)也是類似的情況,接下來Vander聽說漢堡仔的漢堡跟薯條都非常好吃,所以也想加盟其中,然后又在Restaurant基礎(chǔ)上繼續(xù)加入,并且需要添加薯條這種食物,接著三家餐廳都得加入炸薯條工廠生產(chǎn)炸薯條,這太累了,Vander想有沒有更好的方法呢。
此時Panda大師又來了,她一看就覺得這么設(shè)計其實有個很大的問題。
Panda:你這樣的設(shè)計用了繼承來實現(xiàn),但是繼承的關(guān)系在編譯時就定義好了,所以沒法在運行的時候改變父類繼承的實現(xiàn),意思就是說你沒法在運行的時候指定用哪個工廠生產(chǎn)哪種種類的食物。這里就涉及到以前的一個原則,合成/聚合復(fù)用
原則:盡量使用合成/聚合,盡量不要使用類繼承去實現(xiàn)。
Vander:具體應(yīng)該怎么操作呢?不明白合成跟聚合是什么,能不能舉個例子
Panda:請看以下的類圖,馬聚合成馬群(聚合),而四肢是屬于馬的一部分(合成)
Panda:使用這個原則的好處就是,優(yōu)先使用對象的合成/聚合將有助于你保持每個類被封裝,并被集中在單個任務(wù)上,這樣累和類繼承層次會保持較小規(guī)模,并且不太可能增長成為不可控制的龐然大物。說了這么多你可以試試以下的設(shè)計:
Restaurant:
public abstract class Restaurant {
private FoodFactory foodFactory;
protected void makeFood() {
foodFactory.makeFood();
}
public void setFoodFactory(FoodFactory foodFactory) {
this.foodFactory = foodFactory;
}
}
MacDonald:
public class MacDonald extends Restaurant {
private final String RESTAURANT_NAME = this.getClass().getSimpleName();
public MacDonald() {
System.out.println(RESTAURANT_NAME + ":");
}
}
Kentucky:
public class Kentucky extends Restaurant {
private final String RESTAURANT_NAME = this.getClass().getSimpleName();
public Kentucky() {
System.out.println(RESTAURANT_NAME + ":");
}
}
FoodFactory:
public abstract class FoodFactory {
public abstract void makeFood();
}
FriedChickenFactory:
public class FriedChickenFactory extends FoodFactory {
public void makeFood() {
System.out.println(" 生產(chǎn)炸雞");
}
}
HamburgFactory:
public class HamburgFactory extends FoodFactory {
public void makeFood() {
System.out.println(" 生產(chǎn)漢堡");
}
}
OrderFood:
public class OrderFood {
public static void main(String[] args) {
Restaurant restaurant;
restaurant = new MacDonald();
restaurant.setFoodFactory(new FriedChickenFactory());
restaurant.makeFood();
restaurant.setFoodFactory(new HamburgFactory());
restaurant.makeFood();
restaurant = new Kentucky();
restaurant.setFoodFactory(new FriedChickenFactory());
restaurant.makeFood();
restaurant.setFoodFactory(new HamburgFactory());
restaurant.makeFood();
}
}
實現(xiàn)效果:
現(xiàn)在這么設(shè)計有個好處,就是如果要加盟一個新的餐廳,只需要實現(xiàn)多一個Restaurant接口類,如果要添加多一種食物,只需要實現(xiàn)多一個對應(yīng)的食物的工廠就完事了,事實上是利用了前面學(xué)到的“單一責(zé)任原則”,讓創(chuàng)建食物的工作交給了食物工廠,然后通過Restaurant來指定是哪個餐廳的食物,而不是原來那樣將哪個餐廳的哪種食物都糅合在一起了,相當(dāng)于本來的食物工廠又加入了餐廳的元素,導(dǎo)致了一個類有兩種變化的可能。
下面給橋接模式下個定義:
橋接模式:將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。
簡單說明一下這里的抽象部分和實現(xiàn)部分,并不是說抽象類跟實現(xiàn)類的分離,而是說實現(xiàn)的部分就是變化的原因,其實就是將變化的原因獨立出來,讓它們各自去變化,不互相影響。也就是上面的例子中,餐廳的變化跟食物的變化要獨立開來。
最后又到了喜聞樂見的總結(jié)部分,我們又來總結(jié)我們現(xiàn)在現(xiàn)有的設(shè)計模式武器。
面向?qū)ο蠡A(chǔ)
抽象、封裝、多態(tài)、繼承
九大設(shè)計原則
設(shè)計原則一:封裝變化
設(shè)計原則二:針對接口編程,不針對實現(xiàn)編程
設(shè)計原則三:多用組合,少用繼承
設(shè)計原則四:為交互對象之間的松耦合設(shè)計而努力
設(shè)計原則五:對擴(kuò)展開放,對修改關(guān)閉
設(shè)計原則六:依賴抽象,不要依賴于具體的類
設(shè)計原則七:只和你的密友談話
設(shè)計原則八:別找我,我有需要會找你
設(shè)計原則九:類應(yīng)該只有一個改變的理由
模式
橋接模式:將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。