2019.9.10 六大基本原则

设计模式
一:设计模式之六大原则

六大原则是谁?
①单一职责原则 ②开放封闭原则 ③依赖倒置原则
④里式转换原则 ⑤接口隔离原则 ⑥迪米特原则
六大原则是我们提高面向对象编程代码质量的必备原则,另外还是我们理解设计模式的必备前提。

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 的一部分。 
————————————————
版权声明:本文为CSDN博主「oldboy666」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_39923777/article/details/83142410

转载于:https://www.cnblogs.com/LiTZen/p/11496611.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值