C#之常用設計模式(unity版本)
設計模式
一:設計模式之六大原則
六大原則是誰?
①單一職責原則 ②開放封閉原則 ③依賴倒置原則
④裡式轉換原則 ⑤介面隔離原則 ⑥迪米特原則
六大原則是我們提高面向物件程式設計程式碼質量的必備原則,另外還是我們理解設計模式的必備前提。
1.單一職責原則介紹:
單一職責原則:就一個類而言,應該僅有一個引起它變化的原因。簡單的說,就是一個類只負責一項職責(功能)。
簡單點說:一個類只負責一件具體的事情,一個方法只完成一個特定的功能。當你發現一方法完成了兩件事情的時候,就需要適當的重構成兩個方法,類也是一樣的。
在現實生活中有很多典型的例子體現出了單一職責:
比如:一個房子有客廳,有廚房,有衛生間,有臥室;每個房間都有自己“單一的職責/用途”。
2.開放封閉原則介紹:
開放封閉原則:軟體實體(類,方法,模組)應該可以擴充套件,但是不可以修改。開放封閉原則簡稱為開閉原則。
比如說膝上型電腦:我們購買到的任何品牌的筆記本,都是“開放封閉”的。
封閉:整個筆記本是封閉的,且筆記本背部標明瞭“非專業人士,請勿試圖拆卸
或者維修”以及“撕毀保修無效”的封條。
開放:指的是筆記本提供了若干個 USB 的插口,可供我們擴充套件。
簡單分析:
筆記本本身具備鍵盤,觸控板,音響等功能,但是這些往往沒有獨立的外設好。
很多人會選擇購買機械鍵盤,外接滑鼠,外接音響,通過 USB 插口對筆記本原
有的功能進行擴充套件,這是一種正常的操作習慣,擴充套件而不是修改。
很少有人會在筆記本身上直接進行改動的,比如:把所有的鍵盤帽翹開,DIY
成機械鍵盤,拆開機器,更換一個更好的音響。如果你真這樣做了,是有很大的
風險的,風險是你有可能破壞筆記本原有的結構,甚至出現大量的潛在風險。
3.依賴倒置原則介紹:
依賴倒置原則:針對抽象程式設計,不要針對實現程式設計;
高層模組不應該依賴於底層模組,兩個模組都應該依賴於抽象(抽象類/介面)。
依賴倒置原則案例:
案例介紹:一箇中國人和一個美國人上網,他們都需要搜尋,聊天,看視訊,但是他們上網的方式不同,比如美國人搜尋用Google、聊天用MSN、看視訊用Youtube,而中國人搜尋用百度、聊天用QQ或者微信、看視訊用騰訊或者愛奇藝,這個時候我們就可以引入依賴倒置原則
程式碼演示:
4.里氏轉換原則介紹:
①一個軟體實體如果使用的是一個父類的話,那麼一定適用於其子類。而且它察
覺不出父類物件和子類物件的區別。
②在軟體裡面,把父類都替換成它的子類,軟體的行為沒有變化;簡單點說,子
型別必須能夠替換掉它們的父型別。
比如說:Unity 引擎是一個父類,Unity4.x,Unity5.x,Unity2017.x 都是這個父類下的子類。本身具備父類
的功能,同時又都有自己的新功能。
里氏轉換原則名稱的由來:
國外一位姓“裡”的女士發表出來的數學理論,該理論最終以發表者的名字命名。
這種以發表者的名字進行命名的概念有很多,比如:牛頓定律,笛卡爾座標系。
5.迪米特原則介紹:
迪米特原則:也叫做最少知識(知道)原則。
①如果兩個類不必彼此直接通訊,那麼這兩個類就不應當發生直接的相互作用。
如果其中一個類需要呼叫另外一個類的某一個方法的話,可以通過第三者轉發這
個呼叫。
②一個物件應當對其他物件有儘可能少的瞭解。
③迪米特原則主要是強調了類與類之間的鬆耦合。
類與類之間的耦合度越低,越有利於程式碼的複用,一個處於低耦合的類被修改了,
不會對有關係的類造成影響。
比如說:很多公司的董事長都會有自己的助理(祕書),負責幫自己處理公司的零散事情。
比如說:公司需要開會,如果沒有助理,那麼董事長需要親自去通知所有的員工;
但是如果有助理,只需要把開會這件事告訴助理,然後董事長就不需要管了,助
理會去通知所有的員工。
在董事長和公司員工之間,多出來了一個助理,就可以降低董事長和公司員工之
間的耦合度,這樣可以提高董事長的時間價值和效率。
沒有助理:董事長需要面對 N 個員工,1 對 N 的關係;
有了助理:董事長只需要面對助理 1 人,1 對 1 的關係;然後由助理去 1 對 N。
迪米特原則案例演示:
使用程式碼模擬董事長,員工,助理之間的關係。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// EmployeeManager(員工管理器).
/// </summary>
public class EmployeeManager : MonoBehaviour {
private Transform _Transform;
private GameObject prefab_Employee;
private List<GameObject> allEmployeeList = new List<GameObject>();
void Start()
{
_Transform = gameObject.GetComponent<Transform>();
prefab_Employee = Resources.Load<GameObject>("Employee");
CreateAllEmployee();
}
/// <summary>
/// 建立所有員工.
/// </summary>
private void CreateAllEmployee()
{
for(int i = 0; i < 10; i++)
{
GameObject go= GameObject.Instantiate<GameObject>(prefab_Employee,new Vector3(i*1.5f,0f,0f),Quaternion.identity,_Transform);
allEmployeeList.Add(go);
}
}
/// <summary>
/// 通知員工開會.
/// </summary>
public void SendMessageEmployeeMeeting(string time)
{
for(int i = 0; i < allEmployeeList.Count; i++)
{
allEmployeeList[i].GetComponent<Employee>().Meeting(time);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Employee(員工類)
/// </summary>
public class Employee : MonoBehaviour {
/// <summary>
/// 接收會議時間的方法.
/// </summary>
public void Meeting(string time)
{
Debug.Log("我知道了,今天下午"+time+"開會");
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 助理(祕書)類
/// </summary>
public class Secretary : MonoBehaviour {
private EmployeeManager _EmployeeManager;//持有員工管理器指令碼的引用.
void Start()
{
_EmployeeManager = GameObject.Find("EmployeeManager").GetComponent<EmployeeManager>();
}
/// <summary>
/// 通知助理召開會議.
/// </summary>
public void SendMessageSecretaryMeeting(string time)
{
_EmployeeManager.SendMessageEmployeeMeeting(time);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Boss(老闆)類
/// </summary>
public class Boss : MonoBehaviour {
private Secretary _Secretary;//持有祕書指令碼的引用.
void Start()
{
_Secretary = gameObject.GetComponent<Secretary>();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
//通知開會.
_Secretary.SendMessageSecretaryMeeting("五點");
}
}
}
6.介面隔離原則介紹:
介面隔離原則:
①客戶端不應該依賴它不需要的介面;
②一個類對另一個類的依賴應該建立在最小的介面上。
介面概念:
介面是一種能力,是一種規範,當我們對現在已經存在的類的繼承關係進行功能
擴充套件的時候,就可以使用介面來完成相應的工作。
生活中的介面隔離原則:
公司內有很多部門,比如:開發部,業務部,財務部等等,每個部門內都有 N
個員工在工作。現在我把員工要做的事情,定義成一個介面,所有員工都實現這
個介面去做事情。
這個介面中定義的事情有:
工資計算,賬務管理,客戶擴充套件,客戶維護,產品推銷,程式開發,軟體維護。
所有的員工都實現這個介面,去做事情。現在問題就出現了,不管是哪個部門的
員工,在實現了這個介面後,都有很多事情是不需要自己去做的。
當前這個介面就比較臃腫,我們需要對介面進行“功能隔離”:
財務部員工介面:
工資計算,賬務管理;
業務部員工介面:
客戶擴充套件,客戶維護,產品推銷;
開發部員工介面:
程式開發,軟體維護;
這樣對介面功能隔離,細分成不同部門的職責功能介面,不管是現有的員工,還
是以後新加入的員工,只需要實現自己部門對應的介面即可。
設計模式之建立型設計模式
一:簡單工廠模式
簡單工廠模式介紹:
①.模式介紹
簡單工廠模式[Simple Factory],又叫做靜態工廠模式。
簡單工廠模式是由一個工廠物件決定創建出哪一種產品類的例項。
②.模式程式碼結構:
抽象產品角色:簡單工廠模式建立的所有物件的父類,用於描述類的公共部分;
具體產品角色:簡單工廠模式創建出來的具體產品類;
簡單工廠角色:簡單工廠模式的核心,實現了建立產品的內部邏輯。
外部可以通過訪問“簡單工廠”就可以得到具體的產品,而不需要關注產品的具
體建立過程。
測試案例:
實現《90 坦克大戰》遊戲中的 NPC 坦克。【見圖】
NPC 坦克分析:
①在該遊戲中有多種不同型別的 NPC 坦克,我們可以用繼承關係來對坦克的屬
性和行為進行描述;
屬性:移動速度,生命值; 行為:移動,射擊;
②在遊戲中,有一個 NPC 坦克的生成器,我們通過一個按鍵隨機生成一個NPC 坦克。
坦克邏輯實現:
①定義一個TankBase的父類,在父類中實現共有的屬性,用虛方法實現行為;
②定義三個坦克 子類,繼承父類,重寫父類中的虛方法;
③定義一個坦克工廠類,用於例項化和建立坦克 ;
④定義一個坦克管理器,用於坦克的邏輯。
程式碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 所有坦克的父類.
/// </summary>
public class TankBase : MonoBehaviour {
private int moveSpeed;
/// <summary>
/// 移動速度.
/// </summary>
public int MoveSpeed
{
get { return moveSpeed; }
set { moveSpeed = value; }
}
private int lifeValue;
/// <summary>
/// 生命值.
/// </summary>
public int LifeValue
{
get { return lifeValue; }
set { lifeValue = value; }
}
/// <summary>
/// 初始化坦克屬性.
/// </summary>
public void InitTank(int moveSpeed,int lifeValue)
{
this.MoveSpeed = moveSpeed;
this.LifeValue = lifeValue;
}
/// <summary>
/// 坦克移動的虛方法.
/// </summary>
public virtual void TankMove()
{
Debug.Log("坦克移動");
}
/// <summary>
/// 坦克射擊
/// </summary>
public virtual void TankShoot()
{
Debug.Log("開始射擊");
}
public override string ToString()
{
return string.Format("移動速度:{0},生命值:{1}",this.moveSpeed,this.lifeValue);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TankA :TankBase {
public override void TankShoot()
{
base.TankShoot();
Debug.Log("我是坦克A,一次發射一枚炮彈.");
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TankB : TankBase {
public override void TankShoot()
{
base.TankShoot();
Debug.Log("我是坦克B,一次發射二枚炮彈.");
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TankC :TankBase {
public override void TankShoot()
{
base.TankShoot();
Debug.Log("我是坦克C,一次發射三枚炮彈.");
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 坦克工廠類.
/// </summary>
public class TankFctory : MonoBehaviour {
private GameObject prefab_TankA;
private GameObject prefab_TankB;
private GameObject prefab_TankC;
void Awake()
{
prefab_TankA = Resources.Load<GameObject>("TankA");
prefab_TankB = Resources.Load<GameObject>("TankB");
prefab_TankC = Resources.Load<GameObject>("TankC");
}
/// <summary>
/// 建立坦克.
/// </summary>
public TankBase CreateTank(string tankName)
{
TankBase tankBase = null;
switch (tankName)
{
case "TankA":
tankBase = GameObject.Instantiate<GameObject>(prefab_TankA).GetComponent<TankBase>();
tankBase.InitTank(2, 100);
break;
case "TankB":
tankBase = GameObject.Instantiate<GameObject>(prefab_TankB).GetComponent<TankBase>();
tankBase.InitTank(4, 200);
break;
case "TankC":
tankBase = GameObject.Instantiate<GameObject>(prefab_TankC).GetComponent<TankBase>();
tankBase.InitTank(6, 300);
break;
}
return tankBase;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 所有坦克管理器.
/// </summary>
public class TankManager : MonoBehaviour {
private List<string> tankList;
private TankFctory _TankFctory;
void Start()
{
_TankFctory = gameObject.GetComponent<TankFctory>();
tankList = new List<string>();
tankList.Add("TankA");
tankList.Add("TankB");
tankList.Add("TankC");
}
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
int index = Random.Range(0, tankList.Count);
TankBase tankBase = _TankFctory.CreateTank(tankList[index]);
tankBase.TankMove();
tankBase.TankShoot();
Debug.Log(tankBase.ToString());
}
}
}
什麼是 UML 類圖?
UML 類圖指的是用圖形把類,介面,屬性,方法,繼承,實現等等面向物件中
的特點和關係,用圖形的方式展現出來。
簡單工廠模式 UML 簡圖 [見圖]
繼承關係:UML 表示為“實線+空心三角”;實線的尾指向的子類,空心三角
指向的是父類。
依賴關係:UML 表示為“虛線+箭頭”;虛線的尾指向的是依賴者,箭頭指向
的是被依賴者。
二:工廠方法模式
簡單工廠模式的缺點
簡單工廠模式不符合“開發封閉原則”。
當我們需要增加新的產品的時候,需要對坦克工廠類中增加新的 case 語句塊,
現在的坦克工廠類不夠“封閉”,且產品量很多的時候,工廠類中的 case 語句
塊也會很多。
工廠方法模式介紹:
①.模式介紹
工廠方法模式[Factory Method],該模式定義了一個用於建立物件的介面,讓
子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。
工廠方法模式是對簡單工廠模式的進一步抽象和升級,但絕不是替代。
②.模式程式碼結構
抽象產品角色:建立的所有物件的父類,用於描述類的公共部分;
具體產品角色:創建出來的具體產品類;
抽象工廠角色:工廠的抽象父類,定義生成產品的方法;
具體工廠角色:抽象工廠角色的具體子類,每一個具體產品都對應一個工廠。
工廠方法模式演示:
①定義一個坦克工廠介面,介面內實現一個生成坦克的方法;
②為每一個坦克子類都建立一個針對性的工廠類,該工廠類需要實現坦克介面;
③客戶端指令碼使用工廠方法模式。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 坦克工廠介面.
/// </summary>
interface ITankFactory {
TankBase CreateTank(GameObject go);
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 坦克A工廠類.
/// </summary>
public class TankAFactory : ITankFactory
{
public TankBase CreateTank(GameObject go)
{
TankBase tankBase= GameObject.Instantiate<GameObject>(go).GetComponent<TankBase>();
tankBase.InitTank(2,100);
return tankBase;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 坦克B工廠類.
/// </summary>
public class TankBFactory : ITankFactory
{
public TankBase CreateTank(GameObject go)
{
TankBase tankBase = GameObject.Instantiate<GameObject>(go).GetComponent<TankBase>();
tankBase.InitTank(4, 200);
return tankBase;
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 坦克C工廠類.
/// </summary>
public class TankCFactory : ITankFactory
{
public TankBase CreateTank(GameObject go)
{
TankBase tankBase = GameObject.Instantiate<GameObject>(go).GetComponent<TankBase>();
tankBase.InitTank(6, 300);
return tankBase;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 所有坦克管理器.
/// </summary>
public class TankManager : MonoBehaviour {
private List<string> tankList;
private GameObject prefab_TankA;
private GameObject prefab_TankB;
private GameObject prefab_TankC;
void Start()
{
prefab_TankA = Resources.Load<GameObject>("TankA");
prefab_TankB = Resources.Load<GameObject>("TankB");
prefab_TankC = Resources.Load<GameObject>("TankC");
tankList = new List<string>();
tankList.Add("TankA");
tankList.Add("TankB");
tankList.Add("TankC");
}
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
int index = Random.Range(0, tankList.Count);
ITankFactory tankFactory = null;
TankBase tankBase = null;
switch (tankList[index])
{
case "TankA":
tankFactory = new TankAFactory();
tankBase=tankFactory.CreateTank(prefab_TankA);
break;
case "TankB":
tankFactory = new TankBFactory();
tankBase = tankFactory.CreateTank(prefab_TankB);
break;
case "TankC":
tankFactory = new TankCFactory();
tankBase = tankFactory.CreateTank(prefab_TankC);
break;
}
tankBase.TankMove();
tankBase.TankShoot();
Debug.Log(tankBase.ToString());
}
}
}
工廠方法模式 UML 類圖:
三:建造者模式
案例需求:
用面向物件描述 RPG 遊戲中小怪的相關功能邏輯.
小怪組成部分分析:
①自身模型的例項化---[FBX 模型];
②技能釋放時的特效---[ParticleSystem 特效];
③技能釋放或者受傷害時的音效---[MP3 音效];
④頭頂的血條/名字---[UI 預製體]。
說明:一個看似非常簡單的小怪,但是真正把它在遊戲副本中創建出來,最少需
要完成上面 4 類資源的準備。
實現思路:
小怪有自身的控制指令碼,用於控制小怪的邏輯。
血條,特效,音效,都有自己獨立的管理器,管理器內部管理了相關資源。
在例項化小怪的時候,呼叫這些管理器,動態的把血條,特效,音效和小怪關聯
起來。
這樣所有的資源,本身都是獨立的,只有在執行後才會通過程式碼的邏輯把它們關
聯到一起,如果更新,我們只需要替換 Assets 資料夾下對應的資源即可。
本節課就使用第二種思路演示程式碼邏輯。[見圖]
程式碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 小怪自身管理指令碼.
/// </summary>
public class Monster : MonoBehaviour {
private int monsterId;
private string monsterName;
private int monsterLifeValue;
private string monsterAudio;
private string monsterEffect;
private string monsterBloodBar;
/// <summary>
/// 初始化小怪id、名字、生命值.
/// </summary>
public void InitMonster(int id,string name,int lifeValue)
{
this.MonsterId = id;
this.MonsterName = name;
this.MonsterLifeValue = lifeValue;
}
/// <summary>
/// 小怪ID.
/// </summary>
public int MonsterId
{
get { return monsterId; }
set { monsterId = value; }
}
/// <summary>
/// 小怪名字.
/// </summary>
public string MonsterName
{
get { return monsterName; }
set { monsterName = value; }
}
/// <summary>
/// 小怪生命值.
/// </summary>
public int MonsterLifeValue
{
get { return monsterLifeValue; }
set { monsterLifeValue = value; }
}
/// <summary>
/// 小怪音效資源.
/// </summary>
public string MonsterAudio
{
get { return monsterAudio; }
set { monsterAudio = value;}
}
/// <summary>
/// 小怪的特效資源.
/// </summary>
public string MonsterEffect
{
get { return monsterEffect; }
set { monsterEffect = value; }
}
/// <summary>
/// 小怪的血條.
/// </summary>
public string MonsterBloodBar
{
get { return monsterBloodBar; }
set { monsterBloodBar = value; }
}
/// <summary>
/// 顯示血條.
/// </summary>
public void ShowBloodBar()
{
Debug.Log("當前小怪的血條:"+ monsterBloodBar);
}
/// <summary>
/// 播放聲音.
/// </summary>
public void PlayAudio()
{
Debug.Log("播放聲音:"+ monsterAudio);
}
public void PlayEffect()
{
Debug.Log("播放特效:"+ monsterEffect);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 聲音管理器指令碼.
/// </summary>
public class AudioManager{
private Dictionary<int, string> audioDic;
/// <summary>
/// 構造方法初始化音效資料.
/// </summary>
public AudioManager()
{
audioDic = new Dictionary<int, string>();
audioDic.Add(1,"聲音1.mp3");
audioDic.Add(2, "聲音2.mp3");
audioDic.Add(3, "聲音3.mp3");
audioDic.Add(4, "聲音4.mp3");
}
/// <summary>
/// 設定小怪聲音資源.
/// </summary>
public void SetAudio(Monster monster)
{
string tempAudio = null;
audioDic.TryGetValue(monster.MonsterId,out tempAudio);
monster.MonsterAudio = tempAudio;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 小怪血條管理器指令碼.
/// </summary>
public class BloodBarManager {
/// <summary>
/// 設定小怪血條.
/// </summary>
public void SetBloodBar(Monster monster)
{
monster.MonsterBloodBar = "小怪血條:" + monster.MonsterLifeValue;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 特效資源管理器指令碼.
/// </summary>
public class EffectManager {
private Dictionary<int, string> effectDic;
/// <summary>
/// 構造方法初始化特效資料.
/// </summary>
public EffectManager()
{
effectDic = new Dictionary<int, string>();
effectDic.Add(1, "特效1.prefab");
effectDic.Add(2, "特效2.prefab");
effectDic.Add(3, "特效3.prefab");
effectDic.Add(4, "特效4.prefab");
}
/// <summary>
/// 設定小怪特效資源.
/// </summary>
public void SetEffect(Monster monster)
{
string tempEffect = null;
effectDic.TryGetValue(monster.MonsterId, out tempEffect);
monster.MonsterEffect = tempEffect;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 小怪管理器指令碼.
/// </summary>
public class MonsterManager : MonoBehaviour
{
private AudioManager _AudioManager = null;
private EffectManager _EffectManager = null;
private BloodBarManager _BloodBarManager = null;
private GameObject prefab_Monster;
void Start()
{
_AudioManager = new AudioManager();
_EffectManager = new EffectManager();
_BloodBarManager = new BloodBarManager();
prefab_Monster = Resources.Load<GameObject>("Monster");
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Monster monster = GameObject.Instantiate<GameObject>(prefab_Monster).GetComponent<Monster>();
monster.InitMonster(1,"響尾蛇",666);
_AudioManager.SetAudio(monster);
_EffectManager.SetEffect(monster);
_BloodBarManager.SetBloodBar(monster);
monster.ShowBloodBar();
monster.PlayAudio();
monster.PlayEffect();
}
}
缺點與不足
①音效,特效,血條三者的管理器,可以寫成單例模式;
②小怪的建立過程過於複雜,除去例項化小怪物件以外,還需要呼叫三個管理器
來給小怪物件相關屬性賦值。這個過程是比較複雜的,如果漏掉一句,邏輯就容
易出錯。
複雜物件的建立過程,有一個設計模式可以很好的解決該問題,這個模式叫做:
建造者模式。
建造者模式介紹
①.模式介紹
建造者模式[Builder],將一個複雜物件的構建與它的表示分離,使得同樣的構
建過程可以建立不同的表示。
②.模式程式碼結構
產品角色:最終要創建出來的物件的類,本身也可以有父子繼承關係;
抽象建造角色:定義物件的抽象建造步驟;
具體建造角色:繼承抽象建造角色,完成物件建造步驟中具體的邏輯;
指揮者角色:建造者模式的核心,用於完成產品的最終建造。
引入建造者模式後的程式碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 小怪自身管理指令碼.
/// </summary>
public class Monster : MonoBehaviour {
private int monsterId;
private string monsterName;
private int monsterLifeValue;
private string monsterAudio;
private string monsterEffect;
private string monsterBloodBar;
/// <summary>
/// 初始化小怪id、名字、生命值.
/// </summary>
public void InitMonster(int id,string name,int lifeValue)
{
this.MonsterId = id;
this.MonsterName = name;
this.MonsterLifeValue = lifeValue;
}
/// <summary>
/// 小怪ID.
/// </summary>
public int MonsterId
{
get { return monsterId; }
set { monsterId = value; }
}
/// <summary>
/// 小怪名字.
/// </summary>
public string MonsterName
{
get { return monsterName; }
set { monsterName = value; }
}
/// <summary>
/// 小怪生命值.
/// </summary>
public int MonsterLifeValue
{
get { return monsterLifeValue; }
set { monsterLifeValue = value; }
}
/// <summary>
/// 小怪音效資源.
/// </summary>
public string MonsterAudio
{
get { return monsterAudio; }
set { monsterAudio = value;}
}
/// <summary>
/// 小怪的特效資源.
/// </summary>
public string MonsterEffect
{
get { return monsterEffect; }
set { monsterEffect = value; }
}
/// <summary>
/// 小怪的血條.
/// </summary>
public string MonsterBloodBar
{
get { return monsterBloodBar; }
set { monsterBloodBar = value; }
}
/// <summary>
/// 顯示血條.
/// </summary>
public void ShowBloodBar()
{
Debug.Log("當前小怪的血條:"+ monsterBloodBar);
}
/// <summary>
/// 播放聲音.
/// </summary>
public void PlayAudio()
{
Debug.Log("播放聲音:"+ monsterAudio);
}
public void PlayEffect()
{
Debug.Log("播放特效:"+ monsterEffect);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 小怪血條管理器指令碼.
/// </summary>
public class BloodBarManager {
private static BloodBarManager instance;
public static BloodBarManager Instance()
{
if (instance == null)
{
instance = new BloodBarManager();
}
return instance;
}
/// <summary>
/// 設定小怪血條.
/// </summary>
public void SetBloodBar(Monster monster)
{
monster.MonsterBloodBar = "小怪血條:" + monster.MonsterLifeValue;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 特效資源管理器指令碼.
/// </summary>
public class EffectManager {
private Dictionary<int, string> effectDic;
private static EffectManager instance;
public static EffectManager Instance()
{
if (instance == null)
{
instance = new EffectManager();
}
return instance;
}
/// <summary>
/// 構造方法初始化特效資料.
/// </summary>
private EffectManager()
{
effectDic = new Dictionary<int, string>();
effectDic.Add(1, "特效1.prefab");
effectDic.Add(2, "特效2.prefab");
effectDic.Add(3, "特效3.prefab");
effectDic.Add(4, "特效4.prefab");
}
/// <summary>
/// 設定小怪特效資源.
/// </summary>
public void SetEffect(Monster monster)
{
string tempEffect = null;
effectDic.TryGetValue(monster.MonsterId, out tempEffect);
monster.MonsterEffect = tempEffect;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 聲音管理器指令碼.
/// </summary>
public class AudioManager{
private Dictionary<int, string> audioDic;
private static AudioManager instance;
public static AudioManager Instance()
{
if (instance == null)
{
instance = new AudioManager();
}
return instance;
}
/// <summary>
/// 構造方法初始化音效資料.
/// </summary>
private AudioManager()
{
audioDic = new Dictionary<int, string>();
audioDic.Add(1,"聲音1.mp3");
audioDic.Add(2, "聲音2.mp3");
audioDic.Add(3, "聲音3.mp3");
audioDic.Add(4, "聲音4.mp3");
}
/// <summary>
/// 設定小怪聲音資源.
/// </summary>
public void SetAudio(Monster monster)
{
string tempAudio = null;
audioDic.TryGetValue(monster.MonsterId,out tempAudio);
monster.MonsterAudio = tempAudio;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 抽象建造角色類.
/// </summary>
public abstract class Bulider {
public abstract void BuliderAudio();
public abstract void BuliderEffect();
public abstract void BuliderBloodBar();
public abstract GameObject GetResult();
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 小怪構建類.
/// </summary>
public class MonsterBulider : Bulider
{
private Monster monster;
/// <summary>
/// 構造方法內完成初始化.
/// </summary>
public MonsterBulider(int id, string name, int value)
{
monster= GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Monster")).GetComponent<Monster>();
monster.InitMonster(id, name, value);
}
/// <summary>
/// 構造聲音.
/// </summary>
public override void BuliderAudio()
{
AudioManager.Instance().SetAudio(monster);
}
/// <summary>
/// 構造血條.
/// </summary>
public override void BuliderBloodBar()
{
BloodBarManager.Instance().SetBloodBar(monster);
}
/// <summary>
/// 構造特效.
/// </summary>
public override void BuliderEffect()
{
EffectManager.Instance().SetEffect(monster);
}
/// <summary>
/// 返回構造成的小怪物件.
/// </summary>
/// <returns></returns>
public override GameObject GetResult()
{
return monster.gameObject;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 指揮者角色類.
/// </summary>
public class Director {
/// <summary>
/// 完成所有的構造.
/// </summary>
/// <param name="bulider"></param>
public void Construct(Bulider bulider)
{
bulider.BuliderAudio();
bulider.BuliderEffect();
bulider.BuliderBloodBar();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 小怪管理器指令碼.
/// </summary>
public class MonsterManager : MonoBehaviour
{
void Start()
{
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Director director = new Director();
Bulider bulider = new MonsterBulider(1, "響尾蛇", 666);
director.Construct(bulider);
GameObject go = bulider.GetResult();
Monster monster = go.GetComponent<Monster>();
monster.ShowBloodBar();
monster.PlayAudio();
monster.PlayEffect();
}
}
}
建造者模式UML類圖:
聚合關係:UML 表示為“空心菱形+實線+箭頭”。
聚合關係是一種“弱擁有關係”,Director 包含 Builder,但是 Builder 不是
Director 的一部分。
設計模式之結構型設計模式
規劃中。。。。。。。。。。。。。