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中元件的建立,事實上是有一些非常靈活的解決方案可以處理的。實體與元件系統,相當適合於元件的構建,比起工廠方法來說更加靈活和易於擴充套件。