設(shè)計(jì)模式--工廠模式

一、簡(jiǎn)單工廠
舉個(gè)栗子:
開個(gè)披薩店:

Pizza orderPizza() {
    Pizza pizza = new Pizza(); //創(chuàng)建個(gè)pizza
    pizza.prepare(); //備料
    pizza.bake(); //烘烤
    pizza.cut(); //切片
    pizza.box(); //裝盒
}

披薩店不能只有一種披薩,要做各種類型的披薩怎么辦呢?

Pizza orderPizza(String type) {//要做什么pizza就傳入pizza的種類
    Pizza pizza;
if (type.equals(“cheese”)) { //根據(jù)pizza的類型,來(lái)實(shí)例化正確的具體類
        pizza = new CheesePizza();
} else if ...
    
    pizza.prepare(); //備料
    pizza.bake(); //烘烤
    pizza.cut(); //切片
    pizza.box(); //裝盒
}

披薩店擴(kuò)張了,制作的披薩種類更多了,有些披薩賣得不好,不做了,這怎么做呢?
只能在上面代碼里刪掉一些if else,再添加上一些if else。在上面這段代碼中,if else這段會(huì)隨著需求的變化而變化,但對(duì)披薩的備料,烘烤等操作是不會(huì)變化的。

Tips:
開閉原則:
擴(kuò)展開放,對(duì)修改關(guān)閉。一個(gè)軟件實(shí)體應(yīng)該通過(guò)擴(kuò)展來(lái)實(shí)現(xiàn)變化,而不是通過(guò)修改已有代碼來(lái)實(shí)現(xiàn)變化。

很明顯,上面的這種設(shè)計(jì),違背了開閉原則,這就到了使用封裝的時(shí)候了。把會(huì)經(jīng)常修改的if else這段代碼抽離到另一個(gè)對(duì)象中,這個(gè)對(duì)象只負(fù)責(zé)創(chuàng)建披薩。
這個(gè)新對(duì)象SimplePizzaFactory就稱為“工廠”,專門用來(lái)生產(chǎn)不同種類的披薩,orderPizza()就是這個(gè)對(duì)象的客戶,當(dāng)需要披薩時(shí),就叫披薩工廠做一個(gè),至于怎么做,就不用關(guān)心了。
賣披薩分三步:
1.建個(gè)披薩工廠專門做披薩

public class SimplePizzaFactory { //只負(fù)責(zé)創(chuàng)建披薩
    public Pizza createPizza(String type) { //這個(gè)方法為所有用戶實(shí)例化新對(duì)象
        Pizza pizza = null;

        if (type.equals(“cheese”)) { //之前的if else
            pizza = new CheesePizza();
        } else if ...

        return pizza;
     }
}

2.建個(gè)披薩店

public class PizzaStore {
    SimplePizzaFactory factory; //為披薩店P(guān)izzaStore加上對(duì)SimplePizzaFactory的引用
    public PizzaStore (SimplePizzaFactory factory) { //披薩店P(guān)izzaStore的構(gòu)造器,以一個(gè)工廠做參數(shù)
        This.factory = factory;
    }
    public Pizza orderPizza (String type) {
        Pizza pizza;
        pizza = factory.createPizza(type);//通過(guò)傳入類型來(lái)使用工廠加工披薩
        pizza.prepare(); //備料
        pizza.bake(); //烘烤
        ...
        return pizza;
    }
}

3.披薩賣起來(lái)了

pubic class PizzaTest {
    public static void main (String[] args) {
        SimplePizzaFactory factory = new SimplePizzaFactory();//創(chuàng)建一個(gè)披薩工廠
        PizzaStore story = new PizzaStore(factory); //建立一個(gè)披薩店,從披薩工廠里獲取披薩
        store.orderPizza(“Cheese”);//選擇披薩的具體口味
    }
}

簡(jiǎn)單工廠其實(shí)不是一個(gè)設(shè)計(jì)模式,反而比較像一種編程習(xí)慣,把變化的部分單獨(dú)封裝起來(lái)。

二、工廠模式
披薩店有了加盟店啦~~但是每個(gè)加盟店想提供適合自己所在區(qū)域口味的披薩,所以加盟店需要有一個(gè)適合自己的工廠。
還是賣披薩的那三步:
1.建一個(gè)專門生產(chǎn)紐約風(fēng)味的披薩工廠

abstract class PizzaFactory { 
    public abstract Pizza createPizza();
}
public class NYPizzaFactory extent PizzaFactory {//繼承抽象工廠類,創(chuàng)建具體的實(shí)例方法
    public Pizza createPizza(String type) { 
        ... //個(gè)性化定制紐約口味披薩
        return pizza;
    }
}

2.開個(gè)加盟店
到這里發(fā)現(xiàn),加盟店也需要個(gè)性化定制啊,不能通用就是PizzaStore,也得有什么NYPizzaStore啊,那就把披薩店也抽象出來(lái)。

public abstract class PizzaStore { //創(chuàng)建一個(gè)抽象的披薩店P(guān)izzaStore類
    public Pizza orderPizza(String type) {//處理披薩訂單
        Pizza pizza;
        pizza = createPizza(type);//調(diào)用的就是下方的createPizza方法,這個(gè)方法由各個(gè)加盟店自己定義,也就是說(shuō)每個(gè)PizzaStore的子類都會(huì)覆蓋createPizza()方法

        //pizza的后續(xù)制作不變,加盟店無(wú)法影響他們,加盟店只負(fù)責(zé)確定口味,在外部調(diào)用orderPizza,而orderPizza里的createPizza是加盟店自己定義的具體制作什么口味的披薩
        pizza.prepare(); //備料
        pizza.bake(); //烘烤
        ...
        return pizza;
    }
    protected abstract Pizza createPizza(String type);//由各個(gè)加盟店自己決定如何做披薩
}

現(xiàn)在就開個(gè)加盟店

public class NYPizzaStore extends PizzaStore {
    Pizza createPizza(String item) { //必須實(shí)現(xiàn)createPizza()方法,因?yàn)樵赑izzaStore里他是抽象的
        if (item.equals(“cheese”)) { //具體的披薩口味
            return new NYStyleCheesePizza();
        } else if ...
    }
}

3.賣個(gè)紐約風(fēng)味的芝士披薩

public class PizzaTest {
    public Static void main(String[] args) {
        PizzaStroe nyStore = new NYPizzaStore();//建個(gè)紐約加盟店
        Pizza pizza = nyStore.orderPizza(“cheese”);//定個(gè)cheese披薩
    }
}

Tips:
重點(diǎn)解釋abstract Pizza createPizza(String type);


image.png

工廠模式用來(lái)封裝對(duì)象的常見,通過(guò)讓子類決定應(yīng)該創(chuàng)建的對(duì)象,達(dá)到將對(duì)象創(chuàng)建的過(guò)程封裝起來(lái)的目的。
工廠方法模式:定義了一個(gè)創(chuàng)建對(duì)象的接口,但由子類決定要實(shí)例化的類是哪一個(gè)。工廠方法讓類把實(shí)例化推遲到子類。
工廠模式類圖:


image.png

三、抽象工廠模式
抽象工廠模式提供一個(gè)接口,用于創(chuàng)建相關(guān)或依賴對(duì)象的“家族”(敲黑板,重點(diǎn)),而不需要明確指定具體類。
抽象工廠的任務(wù)是定義一個(gè)負(fù)責(zé)創(chuàng)建一組產(chǎn)品的接口,這個(gè)接口內(nèi)的每個(gè)方法都負(fù)責(zé)創(chuàng)建一個(gè)具體產(chǎn)品,同時(shí)利用實(shí)現(xiàn)抽象工廠的子類來(lái)提供這些具體的做法。

工廠方法用的是繼承,而抽象工廠是通過(guò)對(duì)象的組合來(lái)實(shí)現(xiàn)。
再通過(guò)披薩店的例子,來(lái)看看抽象工廠模式。
還是賣披薩的那三步:
1.建立工廠
A.建一個(gè)專門生產(chǎn)紐約風(fēng)味的披薩工廠

abstract class PizzaFactory { 
    public abstract Pizza createPizza();
}
public class NYPizzaFactory extent PizzaFactory {//繼承抽象工廠類,創(chuàng)建具體的實(shí)例方法
    public Pizza createPizza(String type) { 
        ... //個(gè)性化定制紐約口味披薩
        return pizza;
    }
}

B.制作披薩所用的原料需要保證質(zhì)量,就需要建立一家生產(chǎn)原料的工廠,這樣每家加盟店都從這個(gè)原料工廠里進(jìn)貨,確保質(zhì)量。但是各個(gè)加盟店所產(chǎn)披薩的口味不同,所需原料也有細(xì)微差別(紐約的芝士和芝加哥的芝士,口味上是不一樣的),與建立披薩工廠的思想一樣,還是先建立一個(gè)原料生產(chǎn)工廠,然后每個(gè)區(qū)域繼承這個(gè)工廠,來(lái)生產(chǎn)自己各自口味的原料。
定義原料工廠接口,它負(fù)責(zé)創(chuàng)建所有的原料:

public interface PizzaIngredientFactory{
    public Dough createDough(); //生產(chǎn)面團(tuán)
    public Sauce createSauce(); //生產(chǎn)醬料
    ...
}

那么紐約原料工廠生產(chǎn)的原料就是紐約口味的啦

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    public Dough createDough() {
        return new ThinCrustDough();
    }
    public Sauce createSauce() {
        return new MarinaraSauce();
    }
    ...
}

需要使用原料工廠生產(chǎn)出的原料來(lái)制作披薩

public abstract class Pizza {
    Dough dough;
    Sauce sauce;
    ...//制作披薩所需的各種原料

    abstract void prepare();//把prepare()方法聲明成抽象,由不同地區(qū)的原料工廠提供原料

    //之前的烘烤、切片等工序不變
    void back() {
    }
    void cut() {
    }
    ...
}

之后我們就可以使用原料工廠生產(chǎn)的原料來(lái)制作披薩啦,原料的質(zhì)量得到了保證。
制作一個(gè)芝士披薩

public class CheesePizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;
    public CheesePizza (pizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }

    void prepare() {//從原料工廠里獲取原料制作披薩
        dough = ingredientFactory.createDough();
        Sauce = ingredientFactory.createSauce();
        ...
    }
}

Tips:


image.png

2.開個(gè)加盟店

public class NYPizzaStore extends PizzaStore {
    Protected Pizza createPizza(String item) {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        if (item.equals(“cheese”)) {
            //把工廠傳遞給每一個(gè)披薩,以便比薩從工廠中取得原料
            //具體從哪個(gè)工廠(紐約工廠?芝加哥工廠?),由上面那行代碼決定
            pizza = new CheesePizza(ingredientFactory);
        } else if ...
        return pizza;
    }
}

3.賣個(gè)紐約風(fēng)味的芝士披薩

public class PizzaTest {
    public Static void main(String[] args) {
        PizzaStroe nyStore = new NYPizzaStore();//建個(gè)紐約加盟店
        Pizza pizza = nyStore.orderPizza(“cheese”);//定個(gè)cheese披薩
    }
}

看看抽象工廠的類圖


image.png

結(jié)合披薩店再來(lái)看


image.png

結(jié)合上面的類圖再回顧下抽象工廠的定義,抽象工廠的任務(wù)是定義一個(gè)負(fù)責(zé)創(chuàng)建“一組”產(chǎn)品的接口,通過(guò)對(duì)象的“組合”來(lái)實(shí)現(xiàn)。
在披薩店的例子中,創(chuàng)建了三個(gè)接口:披薩,披薩店,披薩原料工廠,通過(guò)組合這三個(gè)接口,實(shí)現(xiàn)了對(duì)各個(gè)加盟店的控制:保證披薩的制作工藝,和原料供應(yīng)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 除了使用new操作符之外,還有更多制造對(duì)象的方法。你講了解到實(shí)例化這個(gè)活動(dòng)不應(yīng)該總是公開的進(jìn)行,也會(huì)認(rèn)識(shí)到初始化經(jīng)...
    pilipalaKing閱讀 443評(píng)論 0 0
  • 一、工廠模式簡(jiǎn)介 意圖定義一個(gè)創(chuàng)建對(duì)象的接口,讓其子類自己決定實(shí)例化哪一個(gè)工廠類,工廠模式使其創(chuàng)建過(guò)程延遲到子類進(jìn)...
    怡紅快綠閱讀 669評(píng)論 0 0
  • 前言:這次我們來(lái)看看工廠模式,工廠模式和抽象工廠模式是在日常開發(fā)中使用非常廣泛的設(shè)計(jì)模式。我們所熟知的sping也...
    __y閱讀 536評(píng)論 0 0
  • 概述 先照搬書上工廠模式的定義,即定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類,工廠方法使一個(gè)類的實(shí)例化延...
    ymjkMaster閱讀 559評(píng)論 0 0
  • 為什么要存款,存款是為了什么? 存款是理財(cái)嗎?什么是理財(cái)?最粗暴的解釋是管理現(xiàn)金的流向。 什么現(xiàn)金流,就是你手上持...
    大麥茶的故事閱讀 279評(píng)論 0 0

友情鏈接更多精彩內(nèi)容