wordpress建站教程主題推廣手段
Unity 設(shè)計(jì)模式 之 創(chuàng)建型模式 -【單例模式】【原型模式】 【建造者模式】
目錄
Unity 設(shè)計(jì)模式 之 創(chuàng)建型模式 -【單例模式】【原型模式】 【建造者模式】
一、簡單介紹
二、單例模式 (Singleton Pattern)
1、什么時(shí)候使用單例模式
2、單例模式的好處
3、使用單例模式的注意事項(xiàng)
三、在 Unity 中使用 單例模式
1、普通型(new)泛型單例模式
2、繼承 MonoBehaviour 的泛型單例模式
3、單例使用方式
4、實(shí)現(xiàn)分析
四、原型模式 (Prototype Pattern)
1、原型模式的原理
2、什么時(shí)候使用原型模式
3、使用原型模式的好處
4、使用原型模式的注意事項(xiàng)
五、在 Unity 中使用 原型模式
1、 定義基類 ShapePrototype
2、創(chuàng)建具體的形狀類
3、創(chuàng)建 ShapeSpawner 負(fù)責(zé)克隆對象
4、設(shè)置場景中的原型對象
5、運(yùn)行效果
六、建造者模式 (Builder Pattern)
1、什么時(shí)候使用建造者模式
2、使用建造者模式的好處
3、建造者模式的注意事項(xiàng)
七、在 Unity 中使用 建造者模式
1、定義房屋類 House
2、定義建造者接口 IHouseBuilder
3、 具體建造者類:木屋建造者 WoodenHouseBuilder 和磚屋建造者 BrickHouseBuilder
4、定義指揮者 Director
5、 在 Unity 場景中使用建造者模式
6、運(yùn)行效果
一、簡單介紹
設(shè)計(jì)模式 是指在軟件開發(fā)中為解決常見問題而總結(jié)出的一套 可復(fù)用的解決方案。這些模式是經(jīng)過長期實(shí)踐證明有效的 編程經(jīng)驗(yàn)總結(jié),并可以在不同的項(xiàng)目中復(fù)用。設(shè)計(jì)模式并不是代碼片段,而是對常見問題的 抽象解決方案,它提供了代碼結(jié)構(gòu)和模塊間交互的一種設(shè)計(jì)思路,幫助開發(fā)者解決特定的設(shè)計(jì)問題。
設(shè)計(jì)模式的特點(diǎn):
- 通用性:設(shè)計(jì)模式針對的是軟件開發(fā)中常見的設(shè)計(jì)問題,適用于各種軟件工程項(xiàng)目。
- 可復(fù)用性:設(shè)計(jì)模式可以在不同項(xiàng)目和環(huán)境下被重復(fù)使用,提高代碼的可維護(hù)性和擴(kuò)展性。
- 可擴(kuò)展性:設(shè)計(jì)模式有助于讓代碼結(jié)構(gòu)更加靈活,易于擴(kuò)展和修改。
- 模塊化:通過設(shè)計(jì)模式,可以減少代碼的耦合性,增強(qiáng)模塊間的獨(dú)立性。
- 提高溝通效率:設(shè)計(jì)模式為開發(fā)者提供了一種通用的設(shè)計(jì)語言,使得團(tuán)隊(duì)成員能夠快速理解并討論設(shè)計(jì)方案。
二、單例模式 (Singleton Pattern)
單例模式 (Singleton Pattern) 是一種創(chuàng)建型設(shè)計(jì)模式,保證一個(gè)類只有一個(gè)實(shí)例,并提供一個(gè)全局訪問點(diǎn)來獲取該實(shí)例。它通過控制類的實(shí)例化過程,確保系統(tǒng)中只有一個(gè)該類的對象存在。
在單例模式中,類的構(gòu)造函數(shù)通常是私有的,防止外部通過 new
來創(chuàng)建對象,類內(nèi)部維護(hù)一個(gè)靜態(tài)實(shí)例,通過公共的靜態(tài)方法提供訪問。
單例模式的特點(diǎn)
- 唯一實(shí)例:單例模式確保一個(gè)類只有一個(gè)實(shí)例,無論系統(tǒng)中的組件如何調(diào)用它。
- 全局訪問點(diǎn):單例模式為客戶端提供一個(gè)全局訪問點(diǎn)(通常是靜態(tài)方法),通過這個(gè)訪問點(diǎn),所有客戶端都能獲得相同的實(shí)例。
- 延遲初始化:可以在首次訪問時(shí)創(chuàng)建該實(shí)例,節(jié)省系統(tǒng)資源(可選)。
1、什么時(shí)候使用單例模式
全局唯一的資源管理:如果一個(gè)類需要控制對某種共享資源(如數(shù)據(jù)庫連接池、文件系統(tǒng)、日志器、配置管理器等)的訪問,并且不允許有多個(gè)實(shí)例同時(shí)存在。
配置或狀態(tài)共享:當(dāng)系統(tǒng)中某個(gè)類需要持有全局配置或共享狀態(tài)時(shí),單例模式可以使得這些狀態(tài)在不同模塊中保持一致。
資源開銷較大的對象:如果一個(gè)類的實(shí)例化代價(jià)較高(如外部資源初始化、復(fù)雜運(yùn)算等),而且只需要一個(gè)實(shí)例時(shí),單例模式可以避免多次重復(fù)的創(chuàng)建操作。
需要嚴(yán)格控制實(shí)例數(shù)量:在某些業(yè)務(wù)邏輯中,嚴(yán)格要求一個(gè)類只能有一個(gè)實(shí)例,否則會(huì)引發(fā)邏輯混亂或資源競爭(如操作系統(tǒng)中的任務(wù)管理器)。
2、單例模式的好處
控制實(shí)例數(shù)量:確保一個(gè)類只生成一個(gè)實(shí)例,避免不必要的內(nèi)存占用,尤其對于管理全局狀態(tài)或資源的對象(如數(shù)據(jù)庫連接、日志系統(tǒng)、配置管理等),控制實(shí)例數(shù)量可以提高系統(tǒng)的穩(wěn)定性。
全局訪問:單例模式提供了一個(gè)全局訪問點(diǎn),這使得某些系統(tǒng)級(jí)別的服務(wù)(如日志系統(tǒng)、資源管理器等)能夠方便地被全局訪問。
節(jié)省資源:避免重復(fù)創(chuàng)建相同對象,減少了資源的消耗,尤其是對于耗費(fèi)較大的對象(如文件系統(tǒng)、數(shù)據(jù)庫連接等)。
線程安全:通過實(shí)現(xiàn)線程安全的單例,可以確保在多線程環(huán)境下,多個(gè)線程對該對象的操作是安全的。
3、使用單例模式的注意事項(xiàng)
-
全局狀態(tài)的復(fù)雜性:雖然單例模式提供全局訪問,但這也意味著它引入了全局狀態(tài),可能導(dǎo)致系統(tǒng)的狀態(tài)管理變得復(fù)雜,特別是在大型系統(tǒng)中。
-
并發(fā)和線程安全:在多線程環(huán)境下,需要確保單例的實(shí)現(xiàn)是線程安全的,否則可能會(huì)出現(xiàn)多個(gè)線程同時(shí)創(chuàng)建實(shí)例的情況,導(dǎo)致數(shù)據(jù)不一致。
-
難以擴(kuò)展:由于單例模式限制了對象的創(chuàng)建數(shù)量,在某些情況下,可能不利于系統(tǒng)的擴(kuò)展或測試。比如,在單元測試中,單例模式可能難以進(jìn)行模擬。
-
濫用風(fēng)險(xiǎn):單例模式提供全局訪問點(diǎn),容易被濫用為全局變量,違背面向?qū)ο笤O(shè)計(jì)中高內(nèi)聚、低耦合的原則。因此,使用時(shí)應(yīng)考慮是否真的有必要將類設(shè)計(jì)為單例。
總之,單例模式 主要用于控制對象的實(shí)例化,確保系統(tǒng)中只有一個(gè)類的實(shí)例,并通過全局訪問點(diǎn)來控制對象的使用。它適用于需要全局共享資源、統(tǒng)一管理的場景,如日志系統(tǒng)、數(shù)據(jù)庫連接池等。盡管單例模式在某些場景下有助于提升系統(tǒng)的穩(wěn)定性和效率,但也應(yīng)謹(jǐn)慎使用,以避免全局狀態(tài)管理復(fù)雜化或?yàn)E用全局訪問帶來的耦合問題。
三、在 Unity 中使用 單例模式
在 Unity 中,實(shí)現(xiàn)一個(gè)線程安全的普通類和MonoBehaviour 類的泛型單例時(shí),必須考慮以下幾點(diǎn):
- 普通類單例:不能被
new
,并且在多線程環(huán)境下線程安全。- MonoBehaviour 單例:由于 MonoBehaviour 的實(shí)例是通過 Unity 的
AddComponent
創(chuàng)建的,不能直接通過new
,也需要保證在多線程環(huán)境下的安全性。
參考類圖如下:
1、普通型(new)泛型單例模式
方法一:
public abstract class Singleton<T> where T : class, new()
{private static T instance = null;// 多線程安全機(jī)制private static readonly object locker = new object();public static T Instance{get{lock (locker){if (instance == null)instance = new T();return instance;}}}
}方法二:using System;
using System.Reflection;/// <summary>
/// 單例
/// 繼承需要一個(gè)非公有的無參構(gòu)造函數(shù)
/// </summary>
/// <typeparam name="T">類名的泛型</typeparam>
public abstract class Singleton<T> where T : class
{private static T instance = null;// 多線程安全機(jī)制private static readonly object locker = new object();public static T Instance{get{// 線程鎖lock (locker){if (null == instance){// 反射獲取實(shí)例var octors = typeof(T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic) ;// 獲取無參數(shù)的非公共構(gòu)造函數(shù)var octor = Array.Find(octors, c => c.GetParameters().Length == 0);// 沒有則提示沒有私有的構(gòu)造函數(shù)if (null == octor){throw new Exception("No NonPublic constructor without 0 parameter");}// 實(shí)例化instance = octor.Invoke(null) as T;}return instance;}}}/// <summary>/// 構(gòu)造函數(shù)/// 避免外界new/// </summary>protected Singleton() { }
}
2、繼承 MonoBehaviour 的泛型單例模式
using UnityEngine;public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{private static T instance = null;private static readonly object locker = new object();private static bool bAppQuitting;public static T Instance{get{if (bAppQuitting){instance = null;return instance;}lock (locker){if (instance == null){// 保證場景中只有一個(gè) 單例T[] managers = Object.FindObjectsOfType(typeof(T)) as T[];if (managers.Length != 0){if (managers.Length == 1){instance = managers[0];instance.gameObject.name = typeof(T).Name;return instance;}else{Debug.LogError("Class " + typeof(T).Name + " exists multiple times in violation of singleton pattern. Destroying all copies");foreach (T manager in managers){Destroy(manager.gameObject);}}}var singleton = new GameObject();instance = singleton.AddComponent<T>();singleton.name = "(singleton)" + typeof(T);singleton.hideFlags = HideFlags.None;DontDestroyOnLoad(singleton);}instance.hideFlags = HideFlags.None;return instance;}}}protected virtual void Awake(){bAppQuitting = false;}protected virtual void OnDestroy(){bAppQuitting = true;}
}
3、單例使用方式
繼承泛型單例模式即可
public class Test1 : MonoSingleton<Test1>{}// 方法一
public class Test2 : Singleton<Test2>{}
// 方法二
public class Test2 : Singleton<Test2>{{private Test2(){}}
4、實(shí)現(xiàn)分析
-
普通類單例:
- 通過 lock 實(shí)現(xiàn)線程安全,避免了多線程環(huán)境下重復(fù)創(chuàng)建實(shí)例的問題。
- 將構(gòu)造函數(shù)設(shè)為
protected
,確保外部不能通過new
關(guān)鍵字實(shí)例化該類。 - 在 Unity 中,適合管理游戲狀態(tài)、配置數(shù)據(jù)等不需要與 Unity 引擎生命周期強(qiáng)綁定的對象。
-
MonoBehaviour 類單例:
- 使用了
lock
機(jī)制確保多線程環(huán)境中的安全性。 - 使用
FindObjectOfType<T>
檢查場景中是否已經(jīng)有該類型的實(shí)例,如果沒有則創(chuàng)建新的對象并添加該組件。 - 通過
DontDestroyOnLoad
確保實(shí)例在場景切換時(shí)不被銷毀,適合音頻管理器、游戲控制器等需要跨場景保持的對象。
- 使用了
這兩種單例的模式在 Unity 中廣泛適用,可以有效地管理全局對象和跨場景對象。
四、原型模式 (Prototype Pattern)
原型模式 (Prototype Pattern) 是一種創(chuàng)建型設(shè)計(jì)模式,它允許通過復(fù)制現(xiàn)有的對象來創(chuàng)建新對象,而不是通過直接實(shí)例化類。這意味著你可以通過克隆原型對象來生成新的實(shí)例,而不必依賴類的構(gòu)造函數(shù)。該模式的核心思想是,通過創(chuàng)建一個(gè)對象的副本(即原型)來避免昂貴的初始化操作。
在 C# 中,通常通過實(shí)現(xiàn) ICloneable
接口或者自定義的克隆方法來實(shí)現(xiàn)原型模式。
1、原型模式的原理
原型模式的工作原理是:
- 定義一個(gè)原型接口或基類,用來提供克隆的方法(如
Clone
)。 - 具體的類實(shí)現(xiàn)該接口,提供自己的克隆方法,該方法返回當(dāng)前對象的深拷貝或淺拷貝。
- 客戶端可以通過克隆原型對象來創(chuàng)建新對象,而無需知道如何構(gòu)造對象。
拷貝的類型可以分為:
- 淺拷貝 (Shallow Copy):只復(fù)制對象的基本數(shù)據(jù)類型,對于引用類型的字段,只復(fù)制引用地址。
- 深拷貝 (Deep Copy):不僅復(fù)制對象的所有值,還遞歸地復(fù)制所有引用對象,創(chuàng)建獨(dú)立的副本。
2、什么時(shí)候使用原型模式
-
需要頻繁創(chuàng)建相似對象時(shí):如果系統(tǒng)需要?jiǎng)?chuàng)建大量相似或結(jié)構(gòu)復(fù)雜的對象時(shí),通過克隆原型對象來生成新對象可以提高性能。
-
對象的創(chuàng)建代價(jià)高昂時(shí):如果對象的初始化非常復(fù)雜,包含很多屬性設(shè)置或涉及昂貴的資源操作(如網(wǎng)絡(luò)連接、文件系統(tǒng)操作),使用原型模式避免了重復(fù)創(chuàng)建過程。
-
避免對象過多的子類化:當(dāng)不希望為了創(chuàng)建新對象而引入更多的子類或擴(kuò)展類時(shí),原型模式可以避免通過繼承創(chuàng)建不同類型對象的繁瑣過程。
-
需要保存對象的歷史狀態(tài)或備份時(shí):如果需要將某個(gè)對象的狀態(tài)備份或在某個(gè)時(shí)刻進(jìn)行復(fù)制(如撤銷操作、快照功能),可以通過原型模式來克隆對象。
3、使用原型模式的好處
-
提高對象創(chuàng)建效率:對于某些對象的創(chuàng)建過程非常復(fù)雜或耗時(shí)時(shí),通過克隆現(xiàn)有對象(即原型)可以避免重復(fù)的復(fù)雜初始化,節(jié)省時(shí)間和資源。
-
避免子類膨脹:通過原型模式,程序不需要通過繼承或工廠模式來生成對象,這可以減少子類的數(shù)量,避免繼承層次的膨脹。
-
動(dòng)態(tài)生成對象:原型模式允許在運(yùn)行時(shí)動(dòng)態(tài)生成對象,不需要事先知道具體類的名稱。
-
減少對象依賴:克隆對象是獨(dú)立于具體類的,原型模式不需要直接依賴構(gòu)造函數(shù),這降低了對象之間的耦合度。
-
靈活性高:通過克隆,可以對現(xiàn)有的對象進(jìn)行修改后創(chuàng)建新的對象,特別適合那些需要頻繁修改對象屬性的場景。
4、使用原型模式的注意事項(xiàng)
-
克隆的深淺拷貝:對于引用類型字段,使用淺拷貝時(shí)需要特別小心,淺拷貝只復(fù)制引用,而不復(fù)制對象本身,可能導(dǎo)致兩個(gè)對象共用同一份數(shù)據(jù)。若需要完全獨(dú)立的對象,必須使用深拷貝。
-
復(fù)雜對象的克隆:當(dāng)對象包含復(fù)雜的嵌套結(jié)構(gòu)或其他依賴時(shí),確保實(shí)現(xiàn)合適的深拷貝邏輯,否則可能會(huì)出現(xiàn)數(shù)據(jù)共享或數(shù)據(jù)覆蓋問題。
-
性能考慮:盡管原型模式避免了對象的重復(fù)構(gòu)造,但深拷貝可能引入較大的性能開銷,特別是在對象嵌套復(fù)雜時(shí)。因此,在性能敏感的場景下要慎重考慮深拷貝的實(shí)現(xiàn)。
-
原型的可變性:當(dāng)通過原型模式創(chuàng)建對象時(shí),如果不慎修改了原型本身的狀態(tài),所有基于該原型創(chuàng)建的對象也可能受到影響。因此在設(shè)計(jì)時(shí),需要確保原型對象的狀態(tài)是安全的。
總之,原型模式 通過復(fù)制現(xiàn)有對象來生成新對象,避免了類構(gòu)造的開銷,特別適用于對象創(chuàng)建代價(jià)高昂或需要?jiǎng)討B(tài)創(chuàng)建對象的場景。它提供了靈活的對象創(chuàng)建方式,減少了類的復(fù)雜性和耦合度。使用時(shí)需要根據(jù)具體需求選擇淺拷貝或深拷貝,并確保對象的可復(fù)制性和獨(dú)立性。
五、在 Unity 中使用 原型模式
在 Unity 中,原型模式可以應(yīng)用于場景中需要頻繁生成的對象,比如 3D 模型(如立方體、球體等)。通過原型模式,我們可以避免每次都從頭實(shí)例化對象,而是通過復(fù)制現(xiàn)有的對象來創(chuàng)建新的實(shí)例。
我們將創(chuàng)建一個(gè)簡單的原型模式應(yīng)用,用于克隆 Unity 中的 3D 對象(立方體、球體等),并根據(jù)用戶輸入生成多個(gè)克隆對象。
步驟:
- 創(chuàng)建一個(gè)基類
ShapePrototype
,它提供克隆接口。- 創(chuàng)建不同的形狀類,如立方體和球體,繼承自
ShapePrototype
。- 使用原型模式通過克隆現(xiàn)有對象來創(chuàng)建新對象,而不是直接創(chuàng)建新對象。
參考類圖如下:
1、 定義基類 ShapePrototype
using UnityEngine;// 定義一個(gè)抽象的原型基類
public abstract class ShapePrototype : MonoBehaviour
{// 定義一個(gè)抽象的克隆方法public abstract ShapePrototype Clone();// 通用的顯示形狀信息的方法public abstract void DisplayInfo();
}
2、創(chuàng)建具體的形狀類
2.1 立方體類
using UnityEngine;public class Cube : ShapePrototype
{// 重寫克隆方法public override ShapePrototype Clone(){// 實(shí)現(xiàn)淺拷貝,復(fù)制當(dāng)前對象的屬性GameObject clone = Instantiate(this.gameObject);return clone.GetComponent<ShapePrototype>();}public override void DisplayInfo(){Debug.Log("This is a Cube.");}
}
2.2 球體類
using UnityEngine;public class Sphere : ShapePrototype
{// 重寫克隆方法public override ShapePrototype Clone(){// 實(shí)現(xiàn)淺拷貝,復(fù)制當(dāng)前對象的屬性GameObject clone = Instantiate(this.gameObject);return clone.GetComponent<ShapePrototype>();}public override void DisplayInfo(){Debug.Log("This is a Sphere.");}
}
3、創(chuàng)建 ShapeSpawner
負(fù)責(zé)克隆對象
using UnityEngine;public class ShapeSpawner : MonoBehaviour
{public ShapePrototype cubePrototype; // 立方體原型public ShapePrototype spherePrototype; // 球體原型private void Update(){// 按下 C 鍵克隆立方體if (Input.GetKeyDown(KeyCode.C)){ShapePrototype cubeClone = cubePrototype.Clone();cubeClone.transform.position = new Vector3(Random.Range(-5, 5), 1, Random.Range(-5, 5));cubeClone.DisplayInfo();}// 按下 S 鍵克隆球體if (Input.GetKeyDown(KeyCode.S)){ShapePrototype sphereClone = spherePrototype.Clone();sphereClone.transform.position = new Vector3(Random.Range(-5, 5), 1, Random.Range(-5, 5));sphereClone.DisplayInfo();}}
}
4、設(shè)置場景中的原型對象
- 創(chuàng)建一個(gè) Unity 場景,并添加一個(gè)空物體
ShapeSpawner
,將上面的ShapeSpawner
腳本掛載到該物體上。 - 在場景中創(chuàng)建一個(gè)立方體和一個(gè)球體,并將它們的
Cube
和Sphere
腳本分別掛載到立方體和球體上。 - 在
ShapeSpawner
腳本的cubePrototype
和spherePrototype
變量中,分別拖拽場景中的立方體和球體作為原型對象。
5、運(yùn)行效果
- 按下
C
鍵:克隆一個(gè)新的立方體,隨機(jī)放置在場景中,并在控制臺(tái)輸出 "This is a Cube." - 按下
S
鍵:克隆一個(gè)新的球體,隨機(jī)放置在場景中,并在控制臺(tái)輸出 "This is a Sphere."
每次克隆都是基于場景中的原型對象,這樣可以避免重新生成對象的開銷,并且保證克隆對象與原型對象的所有屬性相同。
節(jié)省資源,通過克隆現(xiàn)有對象,而不是每次都從頭實(shí)例化對象,可以提高性能,尤其是在場景中需要大量生成對象時(shí);靈活性,可以動(dòng)態(tài)調(diào)整原型對象的屬性,并通過克隆生成新的實(shí)例,而不需要修改對象的創(chuàng)建邏輯;方便擴(kuò)展,如果需要新的形狀,可以輕松擴(kuò)展原型類,無需修改現(xiàn)有代碼。
這種模式在 Unity 的游戲開發(fā)中非常適合用于生成大量相似對象(如敵人、物品、特效等)。
六、建造者模式 (Builder Pattern)
建造者模式 (Builder Pattern) 是一種創(chuàng)建型設(shè)計(jì)模式,它將復(fù)雜對象的構(gòu)建過程與對象的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的對象。建造者模式特別適用于那些構(gòu)建步驟復(fù)雜且具有多種配置的對象。
在建造者模式中,通常有以下幾個(gè)關(guān)鍵部分:
- Builder (建造者):定義了創(chuàng)建產(chǎn)品對象的步驟,通常是一個(gè)抽象類或接口。
- Concrete Builder (具體建造者):實(shí)現(xiàn)了
Builder
接口的類,負(fù)責(zé)具體的構(gòu)建細(xì)節(jié),創(chuàng)建具體的產(chǎn)品對象。- Director (指揮者):負(fù)責(zé)控制構(gòu)建過程,按照一定的順序調(diào)用
Builder
的方法來構(gòu)建對象。- Product (產(chǎn)品對象):最終構(gòu)建的復(fù)雜對象。
1、什么時(shí)候使用建造者模式
構(gòu)建復(fù)雜對象時(shí):如果一個(gè)對象的創(chuàng)建步驟非常復(fù)雜,需要按照一定的順序構(gòu)建多個(gè)部件,建造者模式可以幫助你將這些步驟組織清晰,避免直接調(diào)用復(fù)雜的構(gòu)造函數(shù)。
需要生成多種類型對象時(shí):當(dāng)需要通過相同的構(gòu)建過程生成不同類型或配置的對象時(shí),建造者模式可以幫助你在同一個(gè)框架下靈活構(gòu)建不同的產(chǎn)品。
構(gòu)造函數(shù)參數(shù)過多時(shí):如果一個(gè)類的構(gòu)造函數(shù)有很多可選參數(shù)或者參數(shù)組合非常復(fù)雜,使用建造者模式可以避免構(gòu)造函數(shù)的復(fù)雜性,通過鏈?zhǔn)秸{(diào)用來簡化參數(shù)設(shè)置。
對象的創(chuàng)建流程固定但表示方式多樣時(shí):在一些場景下,產(chǎn)品的創(chuàng)建過程是相同的,但是生成的產(chǎn)品可能有不同的表現(xiàn)方式或配置。此時(shí),建造者模式可以將構(gòu)建流程抽象化,從而生成不同的產(chǎn)品。
2、使用建造者模式的好處
簡化對象構(gòu)建過程:建造者模式將復(fù)雜對象的構(gòu)建步驟集中在一個(gè)地方,減少了創(chuàng)建對象的復(fù)雜度,尤其是當(dāng)對象擁有多個(gè)可選參數(shù)或需要按特定步驟構(gòu)建時(shí)。
靈活構(gòu)建復(fù)雜對象:通過建造者模式,可以將對象的構(gòu)建過程拆分成多個(gè)步驟,允許構(gòu)建者在不同的構(gòu)建過程中創(chuàng)建不同類型的對象或者配置不同的參數(shù)。
代碼清晰、易于維護(hù):建造者模式使代碼更清晰,因?yàn)閷ο蟮臉?gòu)建邏輯被獨(dú)立封裝在
Builder
中,而不是混雜在產(chǎn)品對象內(nèi)部。這使得代碼易于維護(hù)和擴(kuò)展。支持不同的產(chǎn)品變化:同樣的構(gòu)建過程可以生成不同的產(chǎn)品,通過使用不同的建造者,能夠靈活應(yīng)對產(chǎn)品的變化需求。
簡化對象的可變參數(shù)管理:如果對象有很多可選參數(shù),使用建造者模式可以避免復(fù)雜的構(gòu)造函數(shù),提供鏈?zhǔn)秸{(diào)用來設(shè)置參數(shù),使得代碼更加簡潔。
3、建造者模式的注意事項(xiàng)
多個(gè)建造者的協(xié)作:如果你需要構(gòu)建多個(gè)復(fù)雜對象,可以為每種對象提供不同的具體建造者,并通過同一個(gè)指揮者來協(xié)調(diào)構(gòu)建過程。
對象的不可變性:建造者模式可以配合不可變對象使用,確保對象在構(gòu)建完成后無法被修改。
建造順序的靈活性:確保建造者的接口設(shè)計(jì)支持靈活的建造順序,允許客戶端根據(jù)需要選擇不同的建造步驟。
總之,建造者模式通過分離對象的構(gòu)建過程和表示方式,使得構(gòu)建復(fù)雜對象的流程更加清晰和靈活。它非常適合用于那些具有多個(gè)可選參數(shù)、構(gòu)建過程復(fù)雜或者有不同表示方式的對象。建造者模式的使用可以提高代碼的可讀性和可維護(hù)性,同時(shí)減少對象構(gòu)建中的復(fù)雜性。
七、在 Unity 中使用 建造者模式
在 Unity 中,建造者模式可以應(yīng)用于構(gòu)建復(fù)雜的 3D 場景或?qū)ο?。假設(shè)我們要在場景中建造一個(gè)由多個(gè)部分組成的復(fù)雜建筑(如房子),包括地基、墻壁、屋頂?shù)?#xff0c;這正是使用建造者模式的典型場景。
我們將設(shè)計(jì)一個(gè)簡單的場景,展示如何通過建造者模式生成不同配置的房屋。房屋由三部分組成:地基、墻壁和屋頂。通過建造者模式,我們可以靈活地創(chuàng)建不同樣式的房屋。
步驟:
- 定義一個(gè)
House
類,包含地基、墻壁和屋頂。- 定義一個(gè)
IHouseBuilder
接口,聲明創(chuàng)建房屋各部分的方法。- 創(chuàng)建具體的建造者類,如
WoodenHouseBuilder
和BrickHouseBuilder
,實(shí)現(xiàn)不同材料的房屋建造。- 創(chuàng)建一個(gè)
Director
類,用于控制房屋的建造流程。- 在 Unity 場景中通過建造者模式生成不同風(fēng)格的房屋。
參考類圖如下:
1、定義房屋類 House
using UnityEngine;// 房屋類,包含房屋的各個(gè)部分
public class House
{public GameObject Foundation { get; set; }public GameObject Walls { get; set; }public GameObject Roof { get; set; }public void ShowHouseInfo(){Debug.Log("House has been built with Foundation, Walls, and Roof.");}
}
2、定義建造者接口 IHouseBuilder
public interface IHouseBuilder
{void BuildFoundation();void BuildWalls();void BuildRoof();House GetResult();
}
3、 具體建造者類:木屋建造者 WoodenHouseBuilder
和磚屋建造者 BrickHouseBuilder
3.1 木屋建造者
using UnityEngine;public class WoodenHouseBuilder : IHouseBuilder
{private House house = new House();public void BuildFoundation(){house.Foundation = GameObject.CreatePrimitive(PrimitiveType.Cube);house.Foundation.transform.localScale = new Vector3(5, 0.5f, 5);house.Foundation.GetComponent<Renderer>().material.color = Color.gray;}public void BuildWalls(){house.Walls = GameObject.CreatePrimitive(PrimitiveType.Cube);house.Walls.transform.localScale = new Vector3(5, 2.5f, 5);house.Walls.transform.position = new Vector3(0, 1.5f, 0);house.Walls.GetComponent<Renderer>().material.color = Color.yellow; // 木墻}public void BuildRoof(){house.Roof = GameObject.CreatePrimitive(PrimitiveType.Cylinder);house.Roof.transform.localScale = new Vector3(5, 1, 5);house.Roof.transform.position = new Vector3(0, 3f, 0);house.Roof.GetComponent<Renderer>().material.color = Color.red;}public House GetResult(){return house;}
}
3.2 磚屋建造者
using UnityEngine;public class BrickHouseBuilder : IHouseBuilder
{private House house = new House();public void BuildFoundation(){house.Foundation = GameObject.CreatePrimitive(PrimitiveType.Cube);house.Foundation.transform.localScale = new Vector3(5, 0.5f, 5);house.Foundation.GetComponent<Renderer>().material.color = Color.gray;}public void BuildWalls(){house.Walls = GameObject.CreatePrimitive(PrimitiveType.Cube);house.Walls.transform.localScale = new Vector3(5, 2.5f, 5);house.Walls.transform.position = new Vector3(0, 1.5f, 0);house.Walls.GetComponent<Renderer>().material.color = Color.red; // 磚墻}public void BuildRoof(){house.Roof = GameObject.CreatePrimitive(PrimitiveType.Cylinder);house.Roof.transform.localScale = new Vector3(5, 1, 5);house.Roof.transform.position = new Vector3(0, 3f, 0);house.Roof.GetComponent<Renderer>().material.color = Color.green;}public House GetResult(){return house;}
}
4、定義指揮者 Director
public class Director
{private IHouseBuilder houseBuilder;public Director(IHouseBuilder builder){houseBuilder = builder;}// 控制房屋的建造流程public void ConstructHouse(){houseBuilder.BuildFoundation();houseBuilder.BuildWalls();houseBuilder.BuildRoof();}// 獲取構(gòu)建好的房屋public House GetHouse(){return houseBuilder.GetResult();}
}
5、 在 Unity 場景中使用建造者模式
using UnityEngine;public class HouseBuilderExample : MonoBehaviour
{void Start(){// 創(chuàng)建一個(gè)木屋建造者IHouseBuilder woodenHouseBuilder = new WoodenHouseBuilder();Director director = new Director(woodenHouseBuilder);director.ConstructHouse();House woodenHouse = director.GetHouse();woodenHouse.ShowHouseInfo();// 創(chuàng)建一個(gè)磚屋建造者IHouseBuilder brickHouseBuilder = new BrickHouseBuilder();Director brickDirector = new Director(brickHouseBuilder);brickDirector.ConstructHouse();House brickHouse = brickDirector.GetHouse();brickHouse.ShowHouseInfo();}
}
6、運(yùn)行效果
- 當(dāng)運(yùn)行場景時(shí),系統(tǒng)會(huì)根據(jù)不同的建造者生成不同的房屋類型(木屋和磚屋),并將房屋的各個(gè)部分放置在場景中。
WoodenHouseBuilder
會(huì)生成帶有灰色地基、黃色墻壁和紅色屋頂?shù)哪疚荨?/li>BrickHouseBuilder
會(huì)生成帶有灰色地基、紅色磚墻和綠色屋頂?shù)拇u屋。
通過這兩種建造者類的不同實(shí)現(xiàn),我們展示了如何通過建造者模式靈活創(chuàng)建不同類型的復(fù)雜對象。
建造者模式允許分步驟創(chuàng)建對象,并且能夠復(fù)用構(gòu)建過程生成不同類型的產(chǎn)品。它也提高了代碼的可讀性和維護(hù)性,特別是在對象構(gòu)建邏輯復(fù)雜時(shí)。
當(dāng)對象的構(gòu)建步驟固定,但最終產(chǎn)品可能有不同的表現(xiàn)方式時(shí),建造者模式尤其適用。在 Unity 中,這種模式可以用于場景中復(fù)雜對象(如建筑物、場景)的靈活構(gòu)建。