- Android設(shè)計(jì)模式與最佳實(shí)踐
- (英)凱爾·繆
- 1680字
- 2021-02-07 09:26:38
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í),如我們所見,還有許多其他模式可供使用。
- 深度學(xué)習(xí)經(jīng)典案例解析:基于MATLAB
- Django Design Patterns and Best Practices
- Eclipse Plug-in Development:Beginner's Guide(Second Edition)
- Web Development with MongoDB and Node(Third Edition)
- Node.js全程實(shí)例
- Modern C++ Programming Cookbook
- 從程序員角度學(xué)習(xí)數(shù)據(jù)庫技術(shù)(藍(lán)橋杯軟件大賽培訓(xùn)教材-Java方向)
- 超簡(jiǎn)單:Photoshop+JavaScript+Python智能修圖與圖像自動(dòng)化處理
- Java程序設(shè)計(jì)教程
- SQL Server 2012 數(shù)據(jù)庫應(yīng)用教程(第3版)
- Learning Shiny
- C#網(wǎng)絡(luò)編程高級(jí)篇之網(wǎng)頁游戲輔助程序設(shè)計(jì)
- Natural Language Processing with Python Cookbook
- Mastering Assembly Programming
- 梔子貓的奇幻編程之旅:21天探索信息學(xué)奧賽C++編程