这是一个关于ui的故事,ui需要在数值变化的情况下改变自己的显示,ui就是观察者,观察拥有这个hp值的被观察者,当hp改变,被观察者就需要通知观察者改变ui的显示了。
//抽象观察者 using UnityEngine; public class Observer : MonoBehaviour { public virtual void OnValueUpdate(int num) { } }
//抽象被观察者 public interface ISubject { void Attach(Observer o); void Detach(Observer o); void Notify(int num); }
//具体观察者 using UnityEngine.UI; public class HpObserver : Observer { public Text hpText; public override void OnValueUpdate(int num) { hpText.text = num.ToString(); } }
//具体被观察者 using System.Collections.Generic; public class HpSubject:ISubject { private List<Observer> list = new List<Observer>(); public void Attach(Observer o) { list.Add(o); } public void Detach(Observer o) { if (list.Contains(o)) { list.Remove(o); } } public void Notify(int num) { foreach (var i in list) { i.OnValueUpdate(num); } } }
//测试使用 using UnityEngine; public class testObserver : MonoBehaviour { void Start () { HpObserver hp = this.GetComponent<HpObserver>(); ISubject subject = new HpSubject(); subject.Attach(hp); subject.Notify(100); subject.Notify(30); } }
将事先准备好的观察者接口注册到被观察者中,这样被观察者数据发生改变后,就可以通知注册了的观察者发生相应的改变了。注册的行为最好在第三方那里同一管理,方便查找,减少耦合。
这是一个请求处理1,2,3的故事
//抽象处理类 using UnityEngine; public abstract class AResponde { private AResponde up; private string type; public AResponde(string t) { type = t; } public void SetUp(AResponde r) { up = r; } public void HandleRequest(int num) { if (Handle(num)) { Debug.Log(type + "处理了"); } else { if (up != null) { up.HandleRequest(num); } else { Debug.Log("无法处理"); } } } //私有的处理方法 protected abstract bool Handle(int num); }
//具体处理类1,2和3类似处理的2、3 public class OneResponde : AResponde { public OneResponde(string t):base(t){ } protected override bool Handle(int num) { //一顿操作 if (num == 1) return true; return false; } }
//使用测试 using UnityEngine; public class testZRL : MonoBehaviour { void Start () { OneResponde one = new OneResponde("one"); TwoResponde two = new TwoResponde("two"); ThereResponde there = new ThereResponde("three"); there.SetUp(two); two.SetUp(one); there.HandleRequest(1); there.HandleRequest(2); there.HandleRequest(3); there.HandleRequest(10); } }
全程主要在于抽象的处理类的处理请求方法,他负责关注当前处理类能不能完成处理,如果不能就请由上级进行处理,直到有一个处理类能够处理或则不能处理了。
//抽象接受者,用来处理命令的 public abstract class Receive { public abstract void Do(); }
//抽象命令 public interface ICommand { void execude(); }
//具体命令 public class ACommand : ICommand { private Receive mReceive; public ACommand(Receive r) { mReceive = r; } public void execude() { mReceive.Do(); } }
//具体接受者 using UnityEngine; public class AReceive : Receive { public override void Do() { Debug.Log("A Command execude"); } }
//调用者,负责调用命令的 public class Invoker { private ICommand command; public void SetCommand(ICommand c) { command = c; } public void action() { command.execude(); } }
//测试使用 using UnityEngine; public class testCommand : MonoBehaviour { void Start () { AReceive aReceive = new AReceive(); ICommand command = new ACommand(aReceive); Invoker invoker = new Invoker(); invoker.SetCommand(command); invoker.action(); } }
主要分为3种角色
Command类型就是一个命令,本省不包含处理的方法,用于识别。
Receiver接受者,就是接受到命令后,处理的。
Invoker调用者,就是命令的触发者。
//抽象组件基类 public abstract class Component { public int level; public string name; public Component(string n,int l=0) { level = l; name = n; } public abstract void Add(Component cc); public abstract void Remove(Component cc); public abstract void Do(); }
//容器类 using System.Collections.Generic; using UnityEngine; public class Composite : Component { private List<Component> list = new List<Component>(); public Composite(string n) : base(n) { } public override void Add(Component cc) { cc.level = this.level + 1; list.Add(cc); } public override void Do() { Debug.Log("层次" + level + ":" + name); foreach (Component c in list) { c.Do(); } } public override void Remove(Component cc) { list.Remove(cc); } }
//叶子类 using UnityEngine; public class Leaf : Component { public Leaf(string n) : base(n) { } public override void Add(Component cc) { Debug.Log("叶节点无法添加组件"); } public override void Do() { Debug.Log("层次" + level + ":" + name); } public override void Remove(Component cc) { Debug.Log("叶节点无法移除组件"); } }
//测试使用 using UnityEngine; public class testComposite : MonoBehaviour { void Start () { Component root = new Composite("root"); Leaf leaf = new Leaf("leaf1"); root.Add(leaf); Composite com = new Composite("com1"); root.Add(com); Leaf leaf2 = new Leaf("leaf2"); com.Add(leaf2); root.Do(); } }
组合模式其实就是构建一颗树,这里实现统一化让叶子节点和容易都有一样的方法,让小东西组合成大的东西,Do方法遍历层次输出结果,这里用的是先序遍历。
//抽象共享组件 public interface IFlyWeight { bool CheckMaxValue(int val); }
//具体的共享组件 public class EnemyMaxFlyweight : IFlyWeight { private int maxHp = 999999; public bool CheckMaxValue(int val) { if (val > maxHp) return false; return true; } }
using System.Collections.Generic; //工厂类 public class FlyweightFactory { private static FlyweightFactory _instance; private Dictionary<string, IFlyWeight> dic = new Dictionary<string, IFlyWeight>(); private FlyweightFactory() { dic.Add("MaxEnemyHp", new EnemyMaxFlyweight()); } public static FlyweightFactory Instance { get { if (_instance == null) _instance = new FlyweightFactory(); return _instance; } } public IFlyWeight GetFlyWeight(string key) { if (dic.ContainsKey(key)) return dic[key]; return null; } }
//测试使用 using UnityEngine; public class testFlyweight : MonoBehaviour { void Start () { int enemyHp = 1000000; bool isgo = FlyweightFactory.Instance.GetFlyWeight("MaxEnemyHp").CheckMaxValue(enemyHp); if (!isgo) { Debug.Log("生成的敌人生命值超过限制!"); } } }
这里举的例子是关于一类敌人的生成的,假如这类敌人要不停生成,生命不限定,有最大生命值的限定,超过就让他等于最大生命值等,这个最大生命值是固定不变且可以在多个敌人生成器中共享的,所以把这个最大生命值提取出来作为共享元素,当然游戏中,很多的属性都是共享的,只要就只占用一份内存了。
比如说组装机电脑,是很多东西组建成的。
//产品类,复杂的产品是由多种东西组成的 public class ComputeProduct { private string cpu; private string gpu; private string look; public void setCup(string cup) { this.cpu = cpu; } public void setGpu(string gpu) { this.gpu = gpu; } public void setLook(string look) { this.look = look;} }
//构建的抽象类 public interface IBuild { void buildGpu(string gpu); void buildCPU(string cpu); void buildLook(string look); ComputeProduct GetResult(); }
//具体的构造类 public class ComputerBuild : IBuild { private ComputeProduct computer = new ComputeProduct(); public void buildCPU(string cpu) { computer.setCup(cpu); } public void buildGpu(string gpu) { computer.setGpu(gpu); } public void buildLook(string look) { computer.setLook(look); } public ComputeProduct GetResult() { return computer; } }
//指挥类,控制组装的顺序 public class Direction { private IBuild build; public Direction(IBuild build) { this.build = build; } public ComputeProduct BuildComputer(string cpu, string gpu, string look) { build.buildCPU(cpu); build.buildGpu(gpu); build.buildLook(look); return build.GetResult(); } }
//使用 using UnityEngine; public class testBuild : MonoBehaviour { void Start () { IBuild build = new ComputerBuild(); Direction dir = new Direction(build); dir.BuildComputer("ffg", "ttr", "beauty"); } }
如果某个产品是很复杂的,且由一定的组件构造起来的,我们就可以使用构造者模式。易于扩展,但是使用得有点多余的,浪费内存。
比起简单的工厂模式来说,工厂方法模式将控制使用哪个产品由使用工厂控制变成了客户端控制使用哪个工厂(每个工厂对应一个产品)。新加产品时,只需要添加新的具体产品类和对应的工厂就行了,更改客户端逻辑。但是是简单工厂的话,就需要添加一个产品类,然后修改工厂的代码了,不符合开闭原则。
//抽象的工厂 public interface INormalFactory { INormalProduct CreateProduct(); }
//抽象的产品 public interface INormalProduct { void DoSomething(); }
//具体的产品 using UnityEngine; public class ProductA : INormalProduct { public void DoSomething() { Debug.Log("我是产品A"); } }
//具体产品A对用的生成工厂 public class FactoryA : INormalFactory { public INormalProduct CreateProduct() { return new ProductA(); } }
这样的话,如果要添加产品B就简单了,新加两个实现类分别为产品B和工厂B来提供给客户端使用就行了。
//抽象产品类 public interface IOperation { int Cal(int a, int b); }
//具体产品1 public class AddOperation : IOperation { public int Cal(int a, int b) { return a + b; } }
//具体产品2 public class MulOperation : IOperation { public int Cal(int a, int b) { return a * b; } }
//工厂类 public class OperationFactory { public IOperation GetOperation(string name) { switch (name) { case "add": return new AddOperation(); case "mul": return new MulOperation(); default: return null; } } }
//使用测试 using UnityEngine; public class testEasyFactory : MonoBehaviour { private IOperation operation; void Start () { OperationFactory operationFactory = new OperationFactory(); operation = operationFactory.GetOperation("add"); int result = operation.Cal(10, 20); Debug.Log(result); operation = operationFactory.GetOperation("mul"); result = operation.Cal(10, 20); Debug.Log(result); } }
使用工厂类来负责提供给外界需要的具体产品的实例,只需要外界提供需要产品的类型,工厂类维护了所有的产品,从其中找出并提供它的实例出来。
模板方法模式就是将一些固定顺序调用的逻辑提取出来,只需要关注这些顺序中的每个点就可以了。
public abstract class ILogic { public void ChuanFoot() { this.ChuanWaZi(); this.ChuanXiezi(); } protected abstract void ChuanWaZi(); protected abstract void ChuanXiezi(); }
using UnityEngine; public class Hua : ILogic { protected override void ChuanWaZi() { Debug.Log("穿花袜子"); } protected override void ChuanXiezi() { Debug.Log("穿黑皮鞋"); } }
using UnityEngine; public class GreenWaZi : ILogic { protected override void ChuanWaZi() { Debug.Log("穿绿袜子"); } protected override void ChuanXiezi() { Debug.Log("穿花鞋子"); } }
using UnityEngine; public class testMoban : MonoBehaviour { void Start () { Hua hua = new Hua(); hua.ChuanFoot(); GreenWaZi green = new GreenWaZi(); green.ChuanFoot(); } }
这里举了一个很好的例子,哈哈哈,这是一个穿鞋子的故事,人之常情都是先穿袜子再穿鞋子的吧!没有先传鞋子的吧???这样就可以整合起来了,穿袜子先调用,穿鞋子再调用。穿什么袜子和鞋子具体在实现类去实现,在实现类中就不用关心穿袜子先还是穿鞋子先了,增加了代码的重用型。