2018-02-26-設(shè)計模式-工廠模式

除了使用new操作符之外颅围,還有更多制造對象的方法髓抑。你講了解到實例化這個活動不應(yīng)該總是公開的進(jìn)行,也會認(rèn)識到初始化經(jīng)常造成“耦合”問題。你將了解工廠模式如何從復(fù)雜的依賴中幫你脫困鼠冕。
當(dāng)看到new,就會想到具體 所以用的的確是實現(xiàn)胯盯,而不是接口懈费。

new 有什么不對勁?

在技術(shù)上博脑,new沒有錯憎乙,畢竟這是java的基礎(chǔ)部分。真正的犯人是我們的老朋友“改變”叉趣,以及踏實如何影響new的使用的泞边。

針對接口編程,可以隔離掉以后系統(tǒng)可能發(fā)生的一大堆改變疗杉,為什么呢阵谚?如果代碼是針對接口而寫,那么通過多態(tài)烟具,他可以與任何新類 實現(xiàn)該接口梢什。但是,當(dāng)代碼使用大量的具體類時朝聋,等于是自找麻煩绳矩,因為一旦加入新的具體類,就必須改變代碼玖翅。也就是說你的代碼并非“對修改關(guān)閉”翼馆。想用新的具體類型來擴(kuò)展代碼,必須重新打開它金度。
記住应媚,這個設(shè)計應(yīng)該 對擴(kuò)展開放對修改關(guān)閉

如何將實例化具體類的代碼從應(yīng)用中抽離,或者封裝起來猜极,使它們不會干擾應(yīng)用的其他部分中姜?

識別變化的方面

披薩店

Pizza orderPizza(){
//為了讓系統(tǒng)有彈性,我們希望這是一個抽象類或接口跟伏。但如果這樣丢胚,這些類或接口就無法直接實例化。
    Pizza pizza = new Pizza();
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    return pizza;
}

但是你需要更多披薩類型……
所以必須增加一些代碼受扳,來決定適合的披薩類型携龟,然后再“制造”這個披薩。

Pizza orderPizza(String type){
        Pizza pizza ;
        if(type.equals("cheese")){
               pizza=new CheesePizza();
        }else if(type.equals("greek")){
               pizza=new GreekPizza();
        }else if(type.equals("pepperoni")){
               pizza=new PepperoniPizza();
        }
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

但是壓力來自于增加更多的披薩類型
你發(fā)現(xiàn)其他餐廳又多了很多流行風(fēng)味的披薩:ClamPizza(蛤蜊披薩)勘高、VeggiePizza(素食披薩)峡蟋。很明顯你要趕上他們坟桅,需要把這些加入你的菜單中,而最近GreekPizza(希臘披薩)賣的不好蕊蝗,所以你決定將它從菜單中去掉:

Pizza orderPizza(String type) {
    Pizza pizza;
    //這是變化的部分仅乓。隨著時間過去比薩菜單改變,這里就必須一改再改蓬戚。
    if (type.equals("cheese")) {
        pizza = new CheesePizza();
    }
    //此代碼沒有對修改封閉夸楣。如果比薩店改變他所供應(yīng)的比薩風(fēng)味,就得進(jìn)到這里來修改子漩。
    /*else if (type.equals("greek")) {
        pizza = new GreekPizza();
    } */else if (type.equals("pepperoni")) {
        pizza = new PepperoniPizza();
    } else if (type.equals("clam")) {
        pizza = new ClamPizza();
    } else if (type.equals("veggie")) {
        pizza = new VeggiePizza();
    }
    //這里是我們不想改變的地方裕偿。因為比薩的準(zhǔn)備,烘烤痛单,包裝嘿棘,多年都持續(xù)不變,所以這部分的代碼不會改變旭绒,只是發(fā)生這些動作的比薩會改變鸟妙。
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    return pizza;
}

很明顯,如果實例化“某些”具體類挥吵,將使orderPizza()出問題重父,而且也無法讓orderPizza()對修改關(guān)閉,但是忽匈,現(xiàn)在我們已經(jīng)知道哪些會改變房午,哪些不會改變,該是使用封裝的時候了丹允。

封裝創(chuàng)建對象的代碼

我們稱這個新對象為“工廠”郭厌。
工廠處理創(chuàng)建對象的細(xì)節(jié)。一旦有了SimplePizzaFactory,orderPizza()就變成此對象的客戶雕蔽。當(dāng)需要比薩時折柠,就叫比薩工程做一個。那些orderPizza()方法需要知道希臘比薩和蛤蜊比薩的日子不去不復(fù)返了∨現(xiàn)在orderPizza()方法只關(guān)心從工廠得到了一個比薩扇售,而這個比薩實現(xiàn)了Pizza接口,所以它可以調(diào)用prepare()嚣艇、bake()邪驮、cut()溃列、box()來分別進(jìn)行準(zhǔn)備暗挑、烘烤蝗肪、切片、裝盒慌洪。
建立一個簡單披薩工廠

//SimplePizzaFactory是新的類顶燕,他只做一件事情:幫它的客戶創(chuàng)建比薩
public class SimplePizzaFactory {
    //首先,在這個工廠內(nèi)定義一個createPizza()方法冈爹,所有客戶用這個方法來實例化對象涌攻。
    public Pizza createPizza(String type) {
        Pizza pizza = null;

        if ("cheese".equals(type)) {

        } else if ("pepperoni".equals(type)) {

        } else if ("clam".equals(type)) {

        } else if ("veggie".equals(type)) {

        }
        return pizza;
    }
}

重做PizzaStore類
修改我們的客戶代碼,我們要做的是仰仗工廠來為我們創(chuàng)建披薩频伤。

public class PizzaStore {
    //為PizzaStore加上一個對SimplePizzaFactory的引用
    SimplePizzaFactory factory;
    //PizzaStore的構(gòu)造器恳谎,需要一個工廠作為參數(shù)。
    public PizzaStore(SimplePizzaFactory factory) {
        this.factory = factory;
    }
    public Pizza orderPizza(String type) {
        Pizza pizza;
        //把new操作符替換成工廠對象的創(chuàng)建方法憋肖。這里不再使用具體實例化因痛!
        pizza = factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

定義簡單工廠
簡單工廠其實不是一個設(shè)計模式,反而比較像是一種編程習(xí)慣岸更,但由于進(jìn)場被使用鸵膏。所以任務(wù)是工廠模式。
我們來看看新的披薩店類圖:


image.png

再次提醒:在設(shè)計模式中怎炊,所謂的“實現(xiàn)一個接口”并“不一定”表示“寫一個類谭企,并利用implement關(guān)鍵詞來實現(xiàn)某個java接口”∑浪粒“實現(xiàn)一個接口”泛指“實現(xiàn)某個超級類型(可以使類或接口)的某個方法

加盟披薩店

你的披薩店經(jīng)營有成债查,擊敗了競爭者,現(xiàn)在大家都希望比薩店能在自己家附加有加盟店瓜挽。每家加盟店都可能想要提供不同風(fēng)味的披薩(紐約盹廷,芝加哥,加州)久橙。

我們已經(jīng)有一個做法……

如果利用SimplePizzaFactory俄占,寫出三種不同的工廠,分別是
NYPizzaFactory淆衷,ChicagoPizzaFactory颠放,CaliforniaPizzaFactory,各地加盟店都有適合的工廠可以使用吭敢,這是一種做法碰凶。

NYPizzaFactory nyFactory=new NYPizzaFactory();
PizzaStore nyStore=new PizzaStore(nyFactory);
nyFactory.orderPizza("Veggie");

但是你想要多一些質(zhì)量控制……
你發(fā)現(xiàn)加盟店確實采用你的工廠創(chuàng)建披薩,但是其他部分鹿驼,卻開始采用他們自創(chuàng)的流程:烘烤的做法有些差異欲低,不要切片,使用其他廠商的盒子畜晰。
在我們稍早的SimplePizzaFactory代碼之前砾莱,制作披薩的代碼綁在PizzaStore里,但是這么做卻沒有彈性凄鼻,那么腊瑟,該怎么辦聚假。

給披薩店使用的框架

有個做法可讓披薩制作局限于PizzaStore類,而同時又能讓這些加盟店依然可以自由地制作該區(qū)域的風(fēng)味闰非。
所要做的事情膘格,就是把createPizza()方法放回到PizzaStore中,不過要把它設(shè)置成“抽象方法”财松,然后為每個區(qū)域風(fēng)味創(chuàng)建一個PizzaStore的子類瘪贱。

public abstract class PizzaStore {
    
    public Pizza orderPizza(String type) {
        Pizza pizza;
        //現(xiàn)在createPizza()方法從工廠對象中移回PizzaStore
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

    //在PizzaStore里,“工廠方法”現(xiàn)在是抽象的辆毡。
    abstract Pizza createPizza(String type);
}

現(xiàn)在已近有一個PizzaStore作為超類菜秦,讓每個域類型(NYPizzaFactory,ChicagoPizzaFactory舶掖,CaliforniaPizzaFactory)都繼承這個PizzaStore球昨,每個子類各自決定如何制造披薩,

允許子類做決定

別忘了眨攘,PizzaStore已經(jīng)有一個不錯的訂單系統(tǒng)褪尝,由orderPizza()方法負(fù)責(zé)處理訂單,我們現(xiàn)在要讓createPizza()能夠應(yīng)對這些變化來負(fù)責(zé)創(chuàng)建正確種類的披薩期犬,做法是讓PizzaStore的各個子類負(fù)責(zé)定義自己的createPizza()方法河哑,所以我們會得到一些PizzaStore具體的子類,每個子類都有自己的披薩變體龟虎,而任然適合PizzaStore框架璃谨,并使用調(diào)試好的orderPizza()方法。


image.png
讓我們開家比薩店吧

紐約風(fēng)味店:

//NyPizzaStore擴(kuò)展自PizzaStore鲤妥,所以擁有orderPizza()方法(以及其他方法)佳吞。
public class NyPizzaStore extends PizzaStore {
    //createPizza()返回一個Pizza對象,由子類全權(quán)負(fù)責(zé)該實例化哪個具體Pizza
    //必須實現(xiàn)createPizza()方法棉安,因為在PizzaStore里他是抽象的底扳。
    @Override
    Pizza createPizza(String type) {
        Pizza pizza = null;
        if ("cheese".equals(type)) {

        } else if ("pepperoni".equals(type)) {

        } else if ("clam".equals(type)) {

        } else if ("veggie".equals(type)) {

        }
        return pizza;
    }
}

披薩類:

public class Pizza {
    String name;
    String dough;
    String sauce;
    ArrayList toppings = new ArrayList();

    public void prepare() {
        System.out.println("Preparing " + name);
        System.out.println("Tossing dough...");
        System.out.println("Addubg sauce...");
        System.out.println("Addubg toppings...");
        for (int i = 0; i < toppings.size(); i++) {
            System.out.println("  " + toppings.get(i));
        }

    }

    public void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }

    public void cut() {
        System.out.println("Cuting the pizza into diagonal slices");
    }

    public void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    public String getName() {
        return name;
    }
}

我們需要一些具體子類,來定義紐約和芝加哥風(fēng)味的芝士披薩贡耽。


public class NYStyleCheesePizza extends Pizza {

    public NYStyleCheesePizza() {
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
        toppings.add("Grated Reggiano Cheese");
    }
}

public class ChicagoStyleCheesePizza extends Pizza {
    public ChicagoStyleCheesePizza() {
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";
        toppings.add("Shredded Mozzarella Cheese");
    }

    @Override
    public void cut() {
        //這里覆蓋了cut()方法 將比薩切成正方形
        System.out.println("Cutting the pizza into square slices");
    }
}

你已經(jīng)等得夠久了衷模,來吃些披薩吧

       PizzaStore pizzaStore = new NyPizzaStore();
       Pizza pizza = pizzaStore.orderPizza("cheese");
       System.out.println("Ethan ordered a"+pizza.getName()+"\n");
認(rèn)識工廠方法模式的時候終于到了

所有工廠模式都用來封裝對象的創(chuàng)建。工廠方法模式通過讓子類決定該創(chuàng)建的對象是什么蒲赂,來達(dá)到將對象創(chuàng)建的過程封裝的目的阱冶。看看類圖:


創(chuàng)建者.png

產(chǎn)品.png
另一個觀點:平行的類層級
image.png
定義工廠方法模式

工廠方法模式定義了一個創(chuàng)建對象的接口滥嘴,但由子類決定要實例化的類是哪一個木蹬。工廠方法讓類吧實例化推遲到子類。

工廠模式類圖


工廠模式類圖

工廠方法模式能夠封裝具體類型的實例化若皱,抽象的Creator提供了一個創(chuàng)建對象的方法的接口镊叁,在抽象的Creator中尘颓,任何其他實現(xiàn)的方法,都可能使用到這個工廠方法所制造出來的產(chǎn)品晦譬,但只有子類真正實現(xiàn)這個工廠方法并創(chuàng)建產(chǎn)品疤苹。
看看對象依賴
當(dāng)你直接實例化一個對象時,就是在依賴它的具體類蛔添,返回前頁看看這個依賴性很高的比薩店例子痰催,它由披薩店類來創(chuàng)建所有的披薩對象兜辞,而不是委托給工廠迎瞧。

設(shè)計原則

依賴倒置原則 要依賴抽象,不要依賴具體類逸吵。

首先凶硅,這個原則聽起來很像是“針對接口編程,不針對實現(xiàn)編程”扫皱,不是嗎足绅?的確很相似,然而這里更強(qiáng)調(diào)“抽象”韩脑。這個原則說明了:不能讓高層組件依賴底層組件氢妈,而且,不管高層或底層組件段多,兩者都應(yīng)該依賴抽象首量。

讓我們看前面,PizzaStore是“高層組件”进苍,而披薩實現(xiàn)是“底層組件”很清楚地加缘,PizzaStore依賴這些具體披薩類。

現(xiàn)在這個原則告訴我們觉啊,應(yīng)該重寫代碼以便于我們依賴抽象類拣宏,而不依賴具體類。對于高層及底層模塊都應(yīng)該如此杠人。

依賴倒置原則勋乾,究竟倒置在哪里?
在依賴倒置原則中的倒置指的是和一般OO設(shè)計的思考方式完全相反嗡善。
你會注意到前面的底層主鍵現(xiàn)在竟然依賴高層的抽象市俊。同樣的,高層組件現(xiàn)在也依賴相同的抽象滤奈。

倒置你的思考方式

1摆昧、好的,所以你需要試下一個比薩店,你第一件想到的事情是什么蜒程?
嗯绅你!比薩店進(jìn)行準(zhǔn)備伺帘、烘烤、裝盒忌锯、所以我的店必須能制作許多不同風(fēng)味的比薩伪嫁,例如:芝士比薩、素食比薩偶垮、蛤蜊比薩张咳。。似舵。
2脚猾、沒錯!先從頂端開始砚哗,然后往下倒具體類龙助。但是,正如你所看到的你不想讓比薩理會這些具體類蛛芥,要不然比薩店將全都依賴這些具體類√崮瘢現(xiàn)在 倒置 你的想法 、仅淑、称勋、 別從頂端開始,而是從比薩Pizza 開始涯竟,然后想想看能抽象化些什么赡鲜?
是的 芝士比薩、素食比薩昆禽、蛤蜊比薩都是比薩蝗蛙,所以應(yīng)該共享一個Pizza接口。

對了 你想要抽象化一個Pizza醉鳖。

3捡硅、很接近了,但是要這么做盗棵,必須靠一個工廠來經(jīng)這些具體類取出比薩店壮韭。一旦你這么做了,各種不同的具體比薩類型就只能依賴一個抽象纹因,二比薩店也會一來這個抽象喷屋。我們已經(jīng)倒置了一個商店依賴具體類的設(shè)計,而且也倒置了你的思考方式瞭恰。
既然我已經(jīng)有一個比薩抽象屯曹,就可以開始設(shè)計比薩店,而不用理會具體的比薩類了。

下面的指導(dǎo)方針恶耽,能避免在OO設(shè)計中違反依賴倒置原則:

1密任、變量不可以持有具體類的引用。
如果使用new偷俭,就會持有具體類的引用浪讳,你可以改用工廠來避開這樣的做法。
2涌萤、不要讓類派生自具體類淹遵。
如果派生自具體類,你就會以來具體類负溪。請派生自一個抽象(接口或抽象類)透揣。
3、不要覆蓋基類中已實現(xiàn)的方法笙以。
如果覆蓋基類已實現(xiàn)的方法淌实,那么你的基類就不是一個真正適合被繼承的抽象冻辩〔螅基類中已實現(xiàn)的方法,應(yīng)該有所有的子類共享恨闪。

再回到比薩店

有些家門店使用低價原料來增加利潤倘感。必須采取一些手段,確保原料的一致

打算建造一家生產(chǎn)原料的工廠咙咽,并將原料運送到各家加盟店老玛。對于這個做法,現(xiàn)在還剩下一個問題钧敞。家門店坐落在不同的區(qū)域蜡豹,紐約的紅醬料和芝加哥的紅醬料是不一樣的。所以對于紐約和芝加哥溉苛,你準(zhǔn)備兩組不同的原料镜廉。


image.png
建造原料工廠
//這個接口負(fù)責(zé)創(chuàng)建所有的原料
public interface PizzaIngredientFactory {
    public Dough createDough();

    public Sauce createSauce();

    public Cheese createCheese();

    public Veggies[] createVeggies();

    public Pepperoni createPepperoni();

    public Clams createClam();
    //這里有許多類,每個原料都是一個類
    //在接口中愚战,每個原料都有一個對應(yīng)的方法創(chuàng)建該原料
    //如果每個工廠實例內(nèi)部都有某一種通用的機(jī)制需要實現(xiàn)娇唯,就可以吧這個例子改寫成抽象類
}
要做的事情是:

1.為每個區(qū)域建造一個工廠,你需要創(chuàng)建一個繼承自PizzaIngredientFactory的子類來實現(xiàn)每一個創(chuàng)建方法寂玲。
2.實現(xiàn)一組原料類供工廠使用塔插,例如ReggianoCheese,RedPeppers,ThickCrustDough.這些類可以在何時的區(qū)域間共享拓哟。
3.然后你仍然需要將這一切組織起來想许,將新的原料工廠整合進(jìn)舊的PizzaStore代碼中。

創(chuàng)建紐約原料工廠
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    @Override
    public Dough createDough() {
        return new ThinCurstDough();
    }

    @Override
    public Sauce createSauce() {
        return new MarinaraSauce();
    }

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }

    @Override
    public Veggies[] createVeggies() {
        Veggies veggies[] = {new Garlic(),
                new Onion(),
                new Mushroom(),
                new RedPepper()};
        return veggies;
    }

    @Override
    public Pepperoni createPepperoni() {
        return new SlicedPepperoni();
    }

    @Override
    public Clams createClam() {
        return new FreshClams();
    }
}
重做比薩。流纹。谎砾。

工廠已經(jīng)一切就緒,準(zhǔn)備生產(chǎn)高質(zhì)量原料了捧颅,現(xiàn)在我們只需要重做比薩景图,好讓它們使用工廠生產(chǎn)出來的原料。先從抽象的Pizza類開始:

public abstract class Pizza {
    String name;
    Dough dough;
    Sauce sauce;
    Veggies veggies[];
    Cheese cheese;
    Pepperoni pepperoni;
    Clams clams;
    abstract void prepare();
    void bake() {
        System.out.println("Back for 25 minutes at 350");
    }
    void cut() {
        System.out.println("Cutting the pizza into diagonal slices");
    }
    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }
    public String getName() {
        return name;
    }
    void setName(String name) {
        this.name = name;
    }
    public String printString() {
        //這里打印披薩的代碼
        return "";
    }
}
繼續(xù)重做比薩

現(xiàn)在已經(jīng)有一個抽象比薩碉哑,可以開始創(chuàng)建紐約和芝加哥風(fēng)味的比薩了 挚币。從今以后家門店必須直接從工廠取得原料。

public class CheesePizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;

    //要制作比薩扣典,需要工廠提供原料妆毕。所以每個比薩類都需要從構(gòu)造器參數(shù)中得到一個工廠,并把這個工廠存儲在一個實例中
    public CheesePizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }
    @Override
    void prepare() {
        System.out.println("Preparing " + getName());
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
    }
}
    //Pizza的代碼利用相關(guān)的工廠生產(chǎn)原料贮尖。所生產(chǎn)的原料依賴所使用的工廠笛粘,
    // Pizza類根本不關(guān)心這些原料,他只知道如何制作比薩湿硝。
    // 現(xiàn)在薪前,Pizza和區(qū)域原料之間被解耦,無論原料工廠是在洛基山脈還是西北沿岸地區(qū)关斜,Pizza類都可以輕易地復(fù)用完全沒問題示括。
    // sauce = ingredientFactory.createSauce();

    
    //sauce:把pizza的實例變量設(shè)置為此比薩所使用的某種醬料
    //ingredientFactory:這是原料工廠,pizza不在乎使用什么工廠痢畜,只要是原料工廠就行了垛膝。
    //createSauce():方法會返回這個區(qū)域所使用的醬料。如果這是一個紐約原料工廠丁稀,我們將取得大蒜番茄醬料
再回到比薩店
public class NYPizzaStore extends PizzaStore {
    @Override
    Pizza createPizza(String type) {
        Pizza pizza = null;
        //紐約店會用到紐約比薩原料工廠吼拥,由該原料工廠負(fù)責(zé)生產(chǎn)所有紐約風(fēng)味比薩所需的原料。
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        if (type.equals("cheese")) {
             //把工廠傳遞給每一個比薩线衫,以便比薩能從工廠中取得原料凿可。
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("New York Style Cheese PizzaOld");
        } else if (type.equals("veggies")) {
            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("New York Style Veggies PizzaOld");
        } else if (type.equals("clam")) {
            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("New York Style Clam PizzaOld");
        }
        return pizza;

    }
}

一連串的代碼改變;我們到底做了些什么桶雀?

我們引入新類型的工廠矿酵,也就是所謂的抽象工廠,來創(chuàng)建比薩原料家族矗积。
通過抽象工廠所提供的接口全肮,可以創(chuàng)建產(chǎn)品的家族,利用這個接口書寫代碼棘捣,我們的代碼將從實際工廠解耦辜腺,以便在不同上下文中實現(xiàn)各式各樣的工廠,制造出各種不同的產(chǎn)品。例如:不同的區(qū)域评疗,不同的操作系統(tǒng)测砂,不同的外觀及操作。
因為代碼從實際的產(chǎn)品中解耦了百匆,所以我們可以替換不同的工廠來取得不同的行為(例如:取得大蒜番茄醬料砌些,而不是取得番茄醬料)。

定義抽象工廠模式

抽象工廠模式提供一個接口加匈,用于創(chuàng)建相關(guān)或依賴對象的家族存璃,而不需要明確指定具體類。

抽象工廠允許客戶使用抽象的接口來創(chuàng)建一組相關(guān)的產(chǎn)品雕拼,而不需要知道(或關(guān)心)實際產(chǎn)出的具體產(chǎn)品是什么纵东,這樣一來,客戶就從具體的產(chǎn)品中被解耦啥寇。


image.png

這是一張更復(fù)雜的類圖偎球,讓我們從PizzaStore的觀點來看一看它:

image.png

原則 依賴倒置原則: 依賴抽象,不要依賴具體類.

抽象工廠模式-----提供一個接口辑甜,用于創(chuàng)建相關(guān)或依賴對象的家族衰絮,而不需要明確指定具體類。

工廠方法模式-----定義了一個創(chuàng)建對象的接口栈戳,但由子類決定要實例化的嘞是哪一個岂傲。工廠方法讓類吧實例化推遲到子類难裆。

要點

  • 所有的工廠都是用來封裝對象的創(chuàng)建
  • 簡單工廠子檀,雖然不是真正的設(shè)計模式,但仍不失為一個簡單的方法乃戈,可以將客戶長須從具體類解耦
  • 工廠方法使用繼承:把對象的創(chuàng)建委托給子類褂痰,子類實現(xiàn)工廠方法來創(chuàng)建對象
  • 抽象工廠使用對象組合:對象的創(chuàng)建被實現(xiàn)在工廠接口所暴露出來的方法中
  • 所有工廠模式都通過減少應(yīng)用程序和具體類之間的依賴促進(jìn)松耦合
  • 工廠方法允許類將實例化延遲到子類進(jìn)行。
  • 抽象工廠創(chuàng)建相關(guān)的對象家族症虑,而不需要依賴他們的具體類
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缩歪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子谍憔,更是在濱河造成了極大的恐慌匪蝙,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件习贫,死亡現(xiàn)場離奇詭異逛球,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)苫昌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門颤绕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事奥务∥锒溃” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵氯葬,是天一觀的道長挡篓。 經(jīng)常有香客問我,道長帚称,這世上最難降的妖魔是什么瞻凤? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮世杀,結(jié)果婚禮上阀参,老公的妹妹穿的比我還像新娘。我一直安慰自己瞻坝,他們只是感情好蛛壳,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著所刀,像睡著了一般衙荐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浮创,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天忧吟,我揣著相機(jī)與錄音,去河邊找鬼斩披。 笑死溜族,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的垦沉。 我是一名探鬼主播煌抒,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼厕倍!你這毒婦竟也來了寡壮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤讹弯,失蹤者是張志新(化名)和其女友劉穎况既,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體组民,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡棒仍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了邪乍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片降狠。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡对竣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出榜配,到底是詐尸還是另有隱情否纬,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布蛋褥,位于F島的核電站临燃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏烙心。R本人自食惡果不足惜膜廊,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淫茵。 院中可真熱鬧爪瓜,春花似錦、人聲如沸匙瘪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丹喻。三九已至薄货,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碍论,已是汗流浹背谅猾。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留鳍悠,地道東北人税娜。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像贼涩,于是被迫代替她去往敵國和親巧涧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 設(shè)計模式匯總 一遥倦、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 3,906評論 1 15
  • 設(shè)計模式基本原則 開放-封閉原則(OCP)占锯,是說軟件實體(類袒哥、模塊、函數(shù)等等)應(yīng)該可以拓展消略,但是不可修改堡称。開-閉原...
    西山薄涼閱讀 3,753評論 3 13
  • 今天學(xué)習(xí)下最常見的工廠模式,工廠模式細(xì)分下來有三大類: 他們的目標(biāo)都是一樣的:封裝對象的創(chuàng)建艺演。但是實現(xiàn)手段和使用場...
    西木柚子閱讀 2,140評論 7 28
  • 設(shè)計原則: 要依賴抽象却紧,不要依賴具體類 目錄 本文的結(jié)構(gòu)如下: 什么是工廠方法模式 為什么要用該模式 模式的結(jié)構(gòu) ...
    w1992wishes閱讀 1,333評論 0 6
  • 我喜歡吃葡萄桐臊,吃葡萄不吃葡萄皮也不吃葡萄籽。我最愛的是巨峰晓殊,個頭大断凶,甜度不大但有葡萄的清香。 我家常買的卻是玫瑰香...
    苗苗的麻麻閱讀 180評論 0 1