官术网_书友最值得收藏!

1.7 抽象工廠模式

在制作三明治時(shí),面包只是首個(gè)最基本的原料,顯然我們還需要一些餡料。用編程語言來講,這意味著只需簡(jiǎn)單地構(gòu)建另一個(gè)像Bread的接口,可以將其稱為Filling,并為其提供關(guān)聯(lián)的工廠。同樣,我們也可以創(chuàng)建一個(gè)名為Ingredient的全局接口,并將Bread和Filling都作為其樣本。無論使用哪種方式,我們都必須重寫許多代碼。

設(shè)計(jì)模式范例提供了抽象工廠模式,它可能是最適合解決這一難題的方案。簡(jiǎn)單來說,抽象工廠就是創(chuàng)建其他工廠的工廠。額外添加的抽象層可以減少對(duì)主活動(dòng)中上層控制代碼的更改。能夠修改底層結(jié)構(gòu)而不影響前面的結(jié)構(gòu),這是應(yīng)用設(shè)計(jì)模式的主要原因之一。當(dāng)應(yīng)用于復(fù)雜的體系結(jié)構(gòu)時(shí),這種靈活性可以節(jié)省多個(gè)星期的開發(fā)時(shí)間,并且相比其他方法有更多的實(shí)驗(yàn)空間。

使用多個(gè)工廠

下一個(gè)項(xiàng)目和前一個(gè)項(xiàng)目驚人地相似,也理應(yīng)如此。使用模式最大的優(yōu)點(diǎn)之一就是可以復(fù)用結(jié)構(gòu)。你可以繼續(xù)編輯上一個(gè)示例,也可以重新創(chuàng)建一個(gè)。這里,我們將重新開始一個(gè)新項(xiàng)目,希望這樣可以讓模式的講解更清晰。

抽象工廠的工作方式與前面的示例稍有不同。這里,活動(dòng)使用工廠生成器,而工廠生成器又使用抽象工廠類來決定實(shí)際調(diào)用的工廠任務(wù)和創(chuàng)建的具體類。

和之前一樣,我們不關(guān)注輸入和輸出的實(shí)際機(jī)制,而是專注于模式的結(jié)構(gòu)。在繼續(xù)之前,啟動(dòng)一個(gè)新的Android Studio項(xiàng)目。無論你如何命名,請(qǐng)將最低API級(jí)別設(shè)置為你想要的最低版本,并選擇使用Blank Activity(空白活動(dòng))模板。

(1)和之前一樣,開始創(chuàng)建接口,只是這次我們需要兩個(gè)接口:一個(gè)用于面包,另一個(gè)用于餡料。兩個(gè)接口的代碼應(yīng)該如下所示:

    public interface Bread {
        String name();
        String calories();
    }
    public interface Filling {
        String name();
        String calories();
    }

(2)和之前一樣,創(chuàng)建這些接口的實(shí)體類。為了節(jié)省空間,每種接口將只創(chuàng)建兩個(gè)實(shí)體類。因?yàn)樗鼈兊拇a幾乎完全相同,所以這里只給出一個(gè)示例:

    public class Baguette implements Bread {
        @Override
        public String name() {
            return "Baguette";
        }
        @Override
        public String calories() {
            return " : 65 kcal";
        }
    }

(3)創(chuàng)建另一個(gè)叫Brioche的Bread,以及叫Cheese和Tomato的兩種餡料。

(4)接下來,創(chuàng)建一個(gè)類,它可以調(diào)用所有類型的工廠類:

    public abstract class AbstractFactory {
        abstract Bread getBread(String bread);
        abstract Filling getFilling(String filling);
    }

(5)下面創(chuàng)建工廠。首先是BreadFactory:

    public class BreadFactory extends AbstractFactory {
        @Override
        Bread getBread(String bread) {
            if (bread == null) {
                return null;
            }
            if (bread == "BAG") {
                return new Baguette();
            } else if (bread == "BRI") {
                return new Brioche();
            }
            return null;
        }
        @Override
        Filling getFilling(String filling) {
            return null;
        }
    }

(6)然后是FillingFactory:

    public class FillingFactory extends AbstractFactory {
        @Override
        Filling getFilling(String filling) {
            if (filling == null) {
                return null;
            }
            if (filling == "CHE") {
                return new Cheese();
            } else if (filling == "TOM") {
                return new Tomato();
            }
            return null;
        }
        @Override
        Bread getBread(String bread) {
            return null;
        }
    }

(7)最后,添加工廠生成器類:

    public class FactoryGenerator {
        public static AbstractFactory getFactory(String factory) {
            if (factory == null) {
                return null;
            }
            if (factory == "BRE") {
                return new BreadFactory();
            } else if (factory == "FIL") {
                return new FillingFactory();
            }
            return null;
        }
    }

(8)我們可以像之前一樣,使用調(diào)試標(biāo)記測(cè)試代碼:

    AbstractFactory fillingFactory = FactoryGenerator.getFactory("FIL");
    Filling filling = fillingFactory.getFilling("CHE");
    Log.d(DEBUG_TAG, filling.name()+" : "+filling.calories());
    AbstractFactory breadFactory = FactoryGenerator.getFactory("BRE");
    Bread bread = breadFactory.getBread("BRI");
    Log.d(DEBUG_TAG, bread.name()+" : "+bread.calories());

測(cè)試的時(shí)候,Android監(jiān)視器中將產(chǎn)生如下輸出:

    com.example.kyle.abstractfactory D/tag: Cheese : : 155 kcal
    com.example.kyle.abstractfactory D/tag: Brioche : : 85 kcal

至本書末尾時(shí),每種原料都將是一個(gè)復(fù)雜的對(duì)象,具有相關(guān)的圖像、描述文字、價(jià)格、熱值,等等。這時(shí),我們就會(huì)看到堅(jiān)持使用模式的回報(bào)。此處這樣一個(gè)簡(jiǎn)單的示例,只是用來演示創(chuàng)建型模式(例如抽象工廠)如何在不影響客戶端代碼或部署的情況下對(duì)產(chǎn)品進(jìn)行更改。

和前面一樣,可以通過視覺表示來增強(qiáng)我們對(duì)模式的理解,見圖1-9。

圖1-9

想象一下,我們想在菜單中加入軟飲料。它們既不是面包也不是餡料,因此我們需要引入一種全新的對(duì)象。增加軟飲料所需的模式已經(jīng)講過了。我們需要一個(gè)與其他接口相同的新接口,稱為Drink,它將使用相同的name()和calories()方法。具體類(例如IcedTea)可以按照與上面完全相同的方式實(shí)現(xiàn),例如:

    public class IcedTeaimplements Drink {
        @Override
        public String name() {
            return "Iced tea";
        }
        @Override
        public String calories() {
               return " : 110 kcal";
           }
         }

我們需要如下代碼來擴(kuò)展抽象工廠。

    abstract Drink getDrink(String drinkType);

當(dāng)然,我們還需要實(shí)現(xiàn)一個(gè)DrinkFactory類,它和其他工廠有相同的結(jié)構(gòu)。

換言之,我們可以添加、刪除、更改以及徘徊在項(xiàng)目的細(xì)節(jié)之中,而無須擔(dān)心軟件上層邏輯如何感知這些變化。

工廠模式是最常使用的模式之一,它可以且應(yīng)該在很多情景下使用。但是和所有模式一樣,如果不仔細(xì)思考,它可能被過度使用或未充分使用。當(dāng)考慮項(xiàng)目的總體架構(gòu)時(shí),如我們所見,還有許多其他模式可供使用。

主站蜘蛛池模板: 潼关县| 礼泉县| 肇庆市| 象州县| 柳林县| 东阳市| 黄冈市| 渭源县| 兴海县| 乳源| 兴城市| 阿城市| 崇仁县| 咸宁市| 琼海市| 贡觉县| 合水县| 泾源县| 峨边| 华宁县| 德昌县| 电白县| 青阳县| 额济纳旗| 科尔| 玉溪市| 铅山县| 邯郸市| 阳曲县| 天峻县| 阳新县| 额尔古纳市| 育儿| 四会市| 阜城县| 灵石县| 安多县| 富锦市| 桂林市| 甘肃省| 齐齐哈尔市|