1. 程式人生 > >C#之常用設計模式(unity版本)

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 的一部分。 


                                                                 設計模式之結構型設計模式 

規劃中。。。。。。。。。。。。。