close

總覺得找到想要的工作遙遙無期...XD

開始慌了吧哈哈哈哈哈

不過其實著急也沒用... 換個角度想我又沒有要養小孩之類的經濟壓力

只要養活自己的話,現在算是綽綽有餘了

只要在這段期間內能夠持續充實自己,就不算是在浪費時間了

更不用說有些工作根本學不到什麼實質的東西,又累得跟狗一樣做到懷疑人森

與期勉強自己去做那些工作,還是輕鬆又有目標的充實自己吧

 

又到了設計模式的時間

今天來介紹工廠模式,不過裡面又有細分成幾種

有簡單工廠、工廠方法以及抽象工廠三種

 

今天就拿... 披薩店來舉例好了

假設今天要開一間披薩店,可能會有很多種口味的披薩,那麼大概會想把披薩這東西獨立出來,因為它是可變動的部分

所以大概會變成這樣:

class PizzaStore {

public:

    Pizza* orderPizza(string type) {

        Pizza *pizza = nullptr;

        if (type == "cheese") {  // 根據type來決定要產生什麼樣的披薩

            pizza = new cheesePizza();

        else if (type == "clam") {

            pizza = new clamPizza();

        }

        .....

        pizza->prepare();  // 各種pizza內實作的各種方法

        pizza->bake();

        .....

        return pizza;

    }

}

這樣看起來挺合理的吧,直覺地想就會這麼設計

但如果要增加或減少pizza的種類,就必須要去修改上面紅字那段的內容

其實我們要修改的只是pizza的種類,我們希望不要動用到PizzaStore的內容

PizzaStore裡面可能也有賣飲料啊,賣炸雞啊,可能不單純賣披薩嘛

想個辦法把物件之間的關聯性區分開來

 

這就是簡單工廠的概念,我們加入一個簡單工廠的類別到PizzaStore裡面,特別來處理pizza這件事情:

class PizzaStore {

public:

    SimplePizzaFactory* m_factory;  // 簡單工廠

    PizzaStore(SimplePizzaFactory* factory) {

        m_factory = factory;  // 在建構子中傳入工廠的形式

    }

    Pizza* orderPizza(string type) {

        Pizza *pizza = m_factory->createPizza(type);  // 利用工廠產生不同口味的披薩

        pizza.prepare();  // 各種pizza內實作的各種方法

        pizza.bake();

        .....

        return pizza;

    }

}

這樣的話,所有跟披薩相關的東西(前面那段紅字)都包到披薩的簡單工廠裡面去了

之後要修改披薩的種類等等,只要修改工廠的內容就行了

而且在建立PizzaStore的時候也可以傳入不同的工廠

比如說美國的披薩工廠啊、英國的披薩工廠啊等等,又多了一些彈性

這就是簡單工廠,嚴格說起來不算是一個設計模式,比較像是一種習慣吧

把需要修改的地方獨立出來,大概就是這種概念

 

簡單工廠的方式是另外建立一個類別傳入PizzaStore裡面,要執行的時候在依照這個工廠去做事情

其實我們換個角度想,我們何不直接把他合起來呢

只要讓PizzaStore變成是一個抽象類別,然後把createPizza這件事讓他的子類別去繼承實作就可以了

就像以下這樣:

class PizzaStore {

public:

    Pizza* orderPizza(string type) {

        Pizza *pizza = createPizza(type);  // 利用方法產生不同口味的披薩

        pizza.prepare();  // 各種pizza內實作的各種方法

        pizza.bake();

        .....

        return pizza;

    }

    virtual Pizza createPizza(string type) = 0;  // 留給子類別去實作

}

然後子類別可能就長這樣:

class NYPizzaStore : PizzaStore {  // 繼承PizzaStore

public:

    Pizza* orderPizza(string type) {

        Pizza *pizza = createPizza(type);  // 利用方法產生不同口味的披薩

        pizza.prepare();  // 各種pizza內實作的各種方法

        pizza.bake();

        .....

        return pizza;

    }

    Pizza* createPizza(string type) {

        if (type == "cheese") {

              return new NYCheesePizza();

        ....

    }

}

這種方式把簡單工廠包成一個抽象的方法,讓子類別去實作的方式,就是工廠方法模式

在orderPizza()內呼叫createPizza(),但createPizza()是由子類別實作的

所以在設計上,可能就會變成不同地區的PizzaStore去繼承PizzaStore這個抽象類別

然後搭配上不同種類的Pizza(分別去繼承Pizza這個抽象類別)

 

但這樣又會遇到一個問題

前面的方式披薩會搭配不同的PizzaStore,但在披薩本身的製作上是由披薩本身的實作來決定的,從這個角度看,披薩和工廠是分開設計的,這樣很好

但如果說想要把披薩店和披薩的關係拉近一點,比如說披薩的生產要搭配不同地區的原料之類的

這時候我們就可以在不同的PizzaStore送不同的原料去給披薩

但我們同時又不想讓PizzaStore和提供原料這件事情綁在一起

這時候我們可以把簡單工廠的概念帶過來用,在PizzaStore裡面新增一個member負責生產原料,就叫他原料工廠吧

 

這邊簡單寫的話,大概是這樣的概念:

class NYPizzaStore : PizzaStore {

public:

    NYPizzaStore() {

        m_IngredientFactory = new NYIngredientFactory();  // 依照地區有不同的原料工廠,這個工廠是繼承IngredientFactory這個抽象類別的

    }

    Pizza* createPizza(string type) {

        Pizza *pizza = nullptr;

        if (type == "cheese") {

            pizza = new CheesePizza(m_IngredientFactory);  // 把原料工廠傳到披薩內部

        }

        ...

        pizza->prepare();  // 這樣這些pizza的製作都可以依照原料工廠來決定原料

        pizza->bake();

        ...

    }

}

當然pizza的實作也會跟著改變,不過那些細節這邊就不談了

其實前面也有稍微提到一下這個觀念,只是現在這個工廠變成一個抽象類別,要靠子類別繼承他去決定裡面的行為

這個就是抽象工廠模式,由子類去實作抽象類別的函數,執行期的時候讓子類決定實作內容

其實這樣看下來,好像並不是很複雜

只是利用繼承和合成的威力,把不同物件之間的關係鬆綁和連結這樣

不過其實設計模式就是這樣,讓程式的可讀性和擴展性更增加了

 

好啦這篇就這樣了~ 寫一寫突然變得比較清楚了XD

不然去面試都被問倒... 也是亂慘一把的XD

下一個設計模式再見吧~

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 頁頁頁六滴 的頭像
    頁頁頁六滴

    人森很精彩,所以要把所有事情都記起來=ˇ=

    頁頁頁六滴 發表在 痞客邦 留言(0) 人氣()