目录
一、单例模式
二、观察者模式
三、外观模式
四、状态模式
五、命令模式
举例:任务管理器
单例模式的特点
1、只存在唯一一个实例;
2、提供统一对外访问接口,使得全局可对该单例的唯一实例进行访问;3、自行实例化(私有构造函数,不允许外界对其进行实例化)。
优点
1、单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问;
2、意味着在内存中,只存在一个实例,减少了内存开销;
缺点
1、由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
懒汉单例模式
public class DB : MonoBehaviour
{
string[] data;
//私有化构造
DB()
{
}
//自己手动生成当前的类对象
static DB db = new DB();
//向系统提供该单例
public static DB GetDB()
{
return db;
}
}
饿汉单例模式:
public class DB : MonoBehaviour
{
string[] data;
//私有化构造
DB()
{
}
//自己手动生成当前的类对象
static DB db ;
//向系统提供该单例
public static DB GetDB()
{
if (db == null)
{
db = new DB();
}
return db;
}
}
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)
举例:
1、红绿灯与车辆的关系。红绿灯是被观察者,车辆是观察者。红绿灯为单一对象,车辆是多个对象。
2、一个场景内有多只动物,有猫、狗、鸟、老鼠。
我们假设 当猫出来,狗就会跑过来找猫,鸟会飞走,老鼠会逃跑。那么这时候猫就是被观察者,狗、鸟以及老鼠就是观察者。
观察者模式的优点:
1、观察者和被观察者是抽象耦合的,使用委托在观察者中注册事件更能大大降低耦合。
2、建立一套触发机制。
using UnityEngine;
public class Cat : MonoBehaviour
{
//声明一个关于猫的委托
public delegate void WhatIsTheCatDoing();
//再定义一个猫出门的事件
public event WhatIsTheCatDoing theCatOut;
private void Update()
{
if (Input.GetKeyDown(KeyCode.R))
{
CatOut();
}
}
public void CatOut()
{
Debug.Log("猫出门了");
//调用猫出门的事件
theCatOut();
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BeObserved : MonoBehaviour
{
public Cat cat;
public GameObject mouse;
public GameObject bird;
public GameObject Dog;
void Start()
{
//给猫出门添加老鼠逃跑事件
cat.theCatOut += MouseRun;
cat.theCatOut += BirdFly;
cat.theCatOut += DogCome;
}
private void MouseRun()
{
Debug.Log(mouse.name + "逃跑");
}
private void BirdFly()
{
Debug.Log(bird.name + "飞走了");
}
private void DogCome()
{
Debug.Log(Dog.name + "来了");
}
}
定义:外观模式通过提供一个统一的接口,用来访问子系统的一群接口。
在游戏中的应用(Player对象,实现点击一个点Player对象移动到目标点)
Player类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Player:MonoBehaviour
{
NavMeshAgent agent;
Animator ani;
//外界获取到鼠标的点击位置,控制角色移动到该位置
public void WarpTo(Vector3 targetPos)
{
transform.position = targetPos;
}
}
输入管理类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InputManager : MonoBehaviour
{
public Player player;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit ret;
if (Physics.Raycast(ray, out ret))
{
var hitPos = ret.point;
player.WarpTo(hitPos);
}
}
}
}
状态模式包含一下三个角色:
Context(环境类)
State(抽象状态类)
ConcreteState(具体状态类)
案例:假设一个玩家有三种状态(站立、走路、跑步)
抽象状态类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class PlayerState
{
public abstract void Handle(Player player);
}
具体状态类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Standing : PlayerState
{
public override void Handle(Player player)
{
Debug.Log("站立状态");
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Walking : PlayerState
{
public override void Handle(Player player)
{
Debug.Log("走路状态");
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Running : PlayerState
{
public override void Handle(Player player)
{
Debug.Log("跑步状态");
}
}
环境类(利用枚举):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
enum State
{
Standing,
Walking,
Running
}
public class Player : MonoBehaviour
{
private PlayerState playerState;
State currentState;
private void Start()
{
//初始状态为站立状态
currentState = State.Standing;
//检测状态
CheckState();
Request();
}
public void CheckState()
{
switch (currentState)
{
case State.Standing:
playerState = new Standing();
break;
case State.Walking:
playerState = new Walking();
break;
case State.Running:
playerState = new Running();
break;
}
}
public void Request()
{
playerState.Handle(this);
}
}
案例:实现点击Cube随机变色,并记录每一步操作
点击按钮Play可执行刚才的操作
点击按钮Done可将所有按钮变为白色
点击按钮Reset清除所有记录
点击按钮Rewind反转执行刚才的操作
1、抽象命令类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface Icommand
{
void Execute();
void Undo();
}
2、具体抽象类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClickCommand : Icommand
{
private GameObject _cube; //只操作颜色,也可以直接保存MeshRenderer引用,消除每次GetComponent开销
private Color _newColor;
private Color _previousColor;
public ClickCommand()
{
}
public ClickCommand(GameObject cube, Color newColor)
{
_cube = cube;
_newColor = newColor;
}
public void Execute()
{
_previousColor = _cube.GetComponent().material.color;
_cube.GetComponent().material.color = _newColor;
}
public void Undo()
{
_cube.GetComponent().material.color = _previousColor;
}
}
3、调用者
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UserClick : MonoBehaviour
{
ClickCommand clickCommand;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray rayOrigin = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast(rayOrigin, out hitInfo))
{
if (hitInfo.collider.tag == "Cube")
{
Icommand clickCommand = new ClickCommand(hitInfo.collider.gameObject,new Color(Random.value, Random.value, Random.value));
clickCommand.Execute();
CommandManager.AddCommand(clickCommand);
}
}
}
}
}
4、接收者
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CommandManager : MonoBehaviour
{
private static List _commandBuffer = new List();
public static void AddCommand(Icommand newCommand)
{
_commandBuffer.Add(newCommand);
}
//Play按钮回调函数
public void Play()
{
//使用StartCoroutine实现隔一秒执行一项
StartCoroutine(ExecuteAll());
}
IEnumerator ExecuteAll()
{
foreach (var command in _commandBuffer)
{
command.Execute();
yield return new WaitForSeconds(1.0f);
}
Debug.Log("All Commands executed");
}
//Rewind按钮回调函数
public void Rewind()
{
StartCoroutine(UndoAll());
}
IEnumerator UndoAll()
{
foreach (var command in Enumerable.Reverse(_commandBuffer)) //使用Linq实现逆向遍历
{
command.Undo();
yield return new WaitForSeconds(1.0f);
}
Debug.Log("All Commands reversed");
}
//Done按钮回调函数,所有Cube设置为白色
public void Done()
{
var cubes = GameObject.FindGameObjectsWithTag("Cube");
foreach (var cube in cubes)
{
cube.GetComponent().material.color = Color.white;
}
}
//Reset按钮回调函数,清空记录的指令
public void Clear()
{
_commandBuffer.Clear();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log(_commandBuffer.Count);
}
}
}