1. 程式人生 > >Unity3d之設計模式(二)工廠模式

Unity3d之設計模式(二)工廠模式

這個系列的文章,並不會將所有用到的設計模式全部講一遍,事實上我個人認為,並不是所有的設計模式都適用於Unity3D。這裡講的主要還是一些常用的設計模式。 
那麼,本章講的就是常見的構建型模式當中的工廠模式。

簡單工廠模式

講工廠,首先得從簡單工廠說起。 
簡單工廠模式的目的是用來建立不同型別的物件。在GOF的23種模式之中,只講了工程模式的一個例項,但是我們可以根據專案的複雜程度來進行自己的改寫,簡單工廠就是其中的一種寫法。

結構圖


實現

廢話少說,直接上程式碼。

using UnityEngine;

namespace SimpleFactory
{
    #region 產品
    public interface IPhone
    {
        void Version();
    }
    //蘋果手機
    public class PhoneApple : IPhone
    {
        public virtual void Version()
        {
            Debug.Log("蘋果手機");
        }
    }
    //三星手機
    public class PhoneSamsung : IPhone
    {
        public virtual void Version()
        {
            Debug.Log("三星手機");
        }
    }
    #endregion


    #region 工廠
    public class SimpleFactory
    {
        public static IPhone Create(int id)
        {
            switch (id)
            {
                case 1:
                    return new PhoneApple();
                case 2:
                    return new PhoneSamsung();
            }
            return null;
        }
    }
    #endregion
}



簡單工廠模式的Create()方法裡,可以新增各種邏輯,用於建立對應的例項。unity3d中很多時候建立的是遊戲中的物件,這時簡單工廠模式中建立者的引數可以對應prefab的名字。

優點

  • 簡單,可以取名叫『2分鐘內可以學會的設計模式』
  • 實現邏輯清晰,根據不同的建立引數建立對應例項。

名為簡單工廠方法,看起來果然是很簡單,對不對?那麼,本著”simple is best”的邏輯,是不是我們應該大力推廣簡單工廠模式呢? 
答案是「No」。簡單工廠模式有其固有的缺陷,在使用時需要嚴格限定其範圍。

缺陷

讓我們首先考慮一個問題。此處使用的Create()方法,直接決定我們產生例項的邏輯。 
那麼,現在問題來了。 
假如我們不希望通過判斷引數是1還是2,來進行不同例項的生成呢?

 
顯然,一旦我們需要新的邏輯來產生例項的話,我們就不得不對程式碼進行修改。 
當然,從理論上,我們也可以發現簡單工廠模式的一些問題。 
Open-closed原則,即是對擴充套件開放,對修改封閉。使用簡單工廠模式時,很多時候違背了這一原則。同時,由於產生不同例項的方法在可預見的將來有可能會變得很複雜,是否滿足單一職責這一點也值得商榷。 
那麼,我們有辦法解決這個問題嗎?嗯,接下來就是抽象程度更高的方法出場了。

工廠方法

工廠方法與簡單工廠最大的區別,在於工廠方法將工廠進行了抽象,將實現邏輯延遲到工廠的子類。

結構圖


實現

為了讓我們例子更貼近生產環境,在這裡採用一個更加實際的問題。 
現在我們要生產蘋果手機和三星手機 ,我們用工廠方法來生成這兩款手機。
上程式碼 

using UnityEngine;

namespace Factory
{
    #region 產品
    public interface IPhone
    {
        void Version();
    }
    //蘋果手機
    public class ProductApple : IPhone
    {
        public virtual void Version()
        {
            Debug.Log("蘋果手機");
        }
    }
    //三星手機
    public class ProductSamsung : IPhone
    {
        public virtual void Version()
        {
            Debug.Log("三星手機");
        }
    }
    #endregion

    #region 工廠
    public interface IFactory
    {
        IPhone Create();
    }

    public class AppleFactory : IFactory
    {
        public virtual IPhone Create()
        {
            return new ProductApple();
        }
    }

    public class SumsungFactory : IFactory
    {
        public virtual IPhone Create()
        {
            return new ProductSamsung();
        }
    }
    #endregion
}



優點

工廠方法比簡單工廠多了一層抽象。 
由於抽象工廠層的存在,當我們需要修改一個實現的時候,我們不需要修改工廠的角色,只需要修改實現的子類就可以完成這個工作。 
同樣,當我們需要增加一個新產品的時候,我們也不需要修改工廠的角色,只需要增加一個新的實現工廠來完成實現就可以了。 
顯然,這樣更易於擴充套件,並且,整體程式碼的層級結構更加分明,建立實際產品的職責更加單一。 
此外,很顯然客戶在定義工廠角色的時候不需要知道實現子類。只有當實際需要建立的時候,才動態指定子類。這同樣帶來了程式碼的穩定性和最小可知性。

缺陷

顯然,使用工廠方法的程式碼量是多於簡單工廠的。 
同時,每增加一個新的產品,就會增加一個新的工廠類,程式碼的複雜程度自然也隨之上升了。我們會為此建立很多的工廠。

抽象工廠

抽象工廠和工廠方法實際上是很像的,不過抽象工廠增加了另外一個概念,就是產品族。也就是說,一個工廠可以生產一系列的產品,這些產品的定義都在工廠當中。

結構圖


實現

ok。這個模式需要產品和工廠很複雜的專案才需要。直接上程式碼吧,就不加註釋了

using System;
using UnityEngine;

namespace AbstractFactory{

    #region  產品
    public interface IPhone
    {
        void Version();
    }
    public interface IPad
    {
        void Version();
    }

    //蘋果手機
    public class PhoneApple : IPhone
    {
        public virtual void Version()
        {
            Debug.Log("蘋果手機");
        }
    }
    //三星手機
    public class PhoneSamsung : IPhone
    {
        public virtual void Version()
        {
            Debug.Log("三星手機");
        }
    }
    //蘋果pad
    public class PadApple : IPad
    {
        public virtual void Version()
        {
            Debug.Log("蘋果pad");
        }
    }
    //三星pad
    public class PadSamsung : IPad
    {
        public virtual void Version()
        {
            Debug.Log("三星pad");
        }
    }
    #endregion


    #region 工廠
    public interface IFactory
    {
        //pad生產線
        IPad CreatePad();
        //phone生產線
        IPhone CreatePhone();
    }

    //蘋果加工廠
    public class AppleFactory : IFactory
    {
        public IPad CreatePad()
        {
            return new PadApple();
        }

        public IPhone CreatePhone()
        {
            return new PhoneApple();
        }
    }
    //三星加工廠
    public class SumsungFactory : IFactory
    {
        public IPad CreatePad()
        {
            return new PadSamsung();
        }

        public IPhone CreatePhone()
        {
            return new PhoneSamsung();
        }
    }
    #endregion
}


優點

當我們需要增加一個產品族的時候,我們只需要增加一個工廠,實現其中所有產品的實現就行了。 
抽象工廠的設計,使得我們可以很容易的增加一個產品系列。

缺點

抽象工廠當中,產品族的定義使得子類必須去實現所有的產品生產。 
因此,抽象工廠並不適合於橫向擴充套件,即需要增加產品的情況。 
一旦需要增加產品,那麼我們甚至需要去修改抽象的基類。這是比較違反開閉原則,不太符合面向物件設計的做法。

總結

從簡單工廠到工廠方法再到抽象工廠。我們可以看到,抽象的程度越來越高,能夠解決的問題也越來越複雜。 
不過,個人的經驗而言,一般在unity3d當中也頂多用到工廠方法而已。抽象工廠事實上並不是一個很靈活的解決方案。 
而且,對於unity3d中元件的建立,事實上是有一些非常靈活的解決方案可以處理的。實體與元件系統,相當適合於元件的構建,比起工廠方法來說更加靈活和易於擴充套件。