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


                                                                 设计模式之结构型设计模式 

规划中。。。。。。。。。。。。。

  • 35
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值