設計模式之工廠模式


定義

定義一個創建對象的接口,但由子類決定要實例的類是哪一個。工廠方法讓類把實例推遲到子類。

設計原則

要依賴抽象,不要依賴具體的類:不能讓高層組件依賴於底層組件,並且兩者都應該依賴於抽象。

指導方針

  • 變量不可以持有具體類的引用:如果使用new,就會持有具體類的引用。可以用工廠來避開這樣的做法。
  • 不要讓類派生自具體類:如果派生自具體類,你就會依賴具體類。派生自一個抽象。
  • 不要覆蓋基類中已實現的方法:如果覆蓋基類已實現的方法,那么你的基類就不是一個真正適合被繼承的抽象。基類中所有實現的方法,應該由所有子類共享。

抽象工廠模式

提供一個接口,用於創建相關或依賴對象的家族,而不需要明確指定的具體類。

第一次設計(識別變化)

假設我們有一個披薩店,我們需要寫代碼來制造一些不同類型的披薩。
下面來看看我們最開始的設計:

        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();
            }
            else
            {
                pizza = new Pizza();
            }
            pizza.perpare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }

再這里我們根據type傳入的類型來創建對應的pizza,但這里有一個問題,當我們需要修改一些pizza種類的時候,我們就必須要修改里面的代碼。比如:不在提供GreekPizza的pizza,我們就必須刪除創建GreekPizza的代碼。這樣就不符合我們的開放-關閉原則

封裝創建對象代碼

下面,我們將創建pizza對象代碼封裝到一個單獨的對象中,由這個對象專職創建pizza。

    class SimplePizzaFactory
    {
        public Pizza createPizza(string type)
        {
            Pizza pizza = null;

            if (type.Equals("cheese"))
            {
                pizza = new CheesePizza();
            }
            else if (type.Equals("greek"))
            {
                pizza = new GreekPizza();
            }
            else if (type.Equals("pepperoni"))
            {
                pizza = new PepperoniPizza();
            }
            else
            {
                pizza = new Pizza();
            }
        }
    }

重做PizzaStore類

class PizzaStore
    {
        private SimplePizzaFactory factory;

        public PizzaStore(SimplePizzaFactory factory)
        {
            this.factory = factory;
        }

        Pizza orderPizza(string type)
        {
            Pizza pizza=null;

            pizza=factory.createPizza(type);
            pizza.perpare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
    }

類圖


這種簡單的工廠其實並不是一個設計模式,反而比較像是一種編程習慣。

使用框架

下面我們把createPizza的方法放回PizzaStore中,但是要把它設置成"抽象方法",然后為每個區域創建不同的PizzaStore子類。讓每個子類各自決定如何制造披薩。

public abstract class PizzaStore
    {
        //private SimplePizzaFactory factory;

        //public PizzaStore(SimplePizzaFactory factory)
        //{
        //    this.factory = factory;
        //}

        Pizza orderPizza(string type)
        {
            Pizza pizza = null;

           // factory.createPizza(type);
           //從工廠對象中移回PizzaStore中
            pizza = createPizza(type);
            pizza.perpare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }


        //工廠對象移到這里
        public abstract Pizza createPizza(string type);
    }
    }

在這里,orderPizza會對Pizza對象做許多的事情,但並不知道究竟是哪一種披薩,這里其實就是解耦。

開一家披薩店

        public override Pizza createPizza(string type)
        {
            if (type.Equals("cheese"))
            {
                return new CheesePizza();
            }
            //根據類型不同,創建其他對象
            return null;
        }

工廠模式

所有工廠模式都用來封裝對象創建的。

創建者類


Creator類是一個抽象類,它定義了一個抽象的工廠方法,讓子類實現此方法制造產品。
子類可以利用createPrizza創建自己的產品。

產品類

對於上面的PizzaStore來說,Pizza就是產品。

定義工廠方法模式

工廠方法模式:定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法讓類把實例化推出到子類。

依賴倒置原則

當你直接實例化一個對象時,就是在依賴它的具體類。
在代碼里減少對於具體類依賴是件"好事"。這個原則就是依賴倒置原則——要依賴抽象,不要依賴具體類。
不能讓高層組件(由其他底層組件定義其行為的類)賴低層組件,不管高層還是底層,兩者都應該依賴與抽象。
上面示例應用工廠模式后類圖:

可以看到,高層組件(PizzaStore)和底層組件都依賴了Pizza抽象。

幾個指導方針幫助你遵循此原則

  • 變量不可以持有具體的引用
  • 不要讓類派生自具體類
  • 不要覆蓋基類中已經實現的方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM