我们聊回上一次做的小游戏,分析下我写的Model有什么缺陷
上一篇的链接:https://blog.csdn.net/keven2148/article/details/79760734
GameController了解三种游戏物体并有他们的引用,三种物体想要获得其他的属性(例如Man的excuse需要知道boat和land的空位数组)可以通过GameController来引用,而不用显式相互引用,使耦合松散
游戏和一般工程不同,实例的生成大都是有计划性的,只有特定的一整套实例同时存在才有意义。在游戏内容不发生机制上的颠覆性改变(比如咱不过河了,咱改成漂流游戏)的前提下,改动Land,Man,Boat的规则都不会影响到其他三个类的正常使用,是容易维护的
但这里有一个问题,我们的InputController默认只会发出一个命令——excuse,excuse的逻辑分别由两个类自己处理,如果我们需要增加命令,例如让人或者船自杀,让人或者船变成金色!并且这些命令是对两个物体都同时有效的,也就是说,如果要增加命令,不仅要改动接口,还要同时修改boat和man类,显然不符合封闭开放原则,所以我们需要把命令的逻辑封装后分离出来。
这里我选择使用“访问者模式”
访问者模式:表示一个作用于某对象结构的各元素的操作。它使你可以在不改变元素的类的前提下定义作用于这些元素的新操作(——GOF)
仔细读读访问者模式的定义,封装了对元素的操作,并且“不改变元素的类”,正好,我们的boat和man是不需要改变的(变了这个游戏就不叫和尚与魔鬼了),“定义新操作”,是的,我们需要定义更多的操作。这个模式正是我们需要的
核心代码:
Visitor.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class Visitor{ public abstract void VisitMan(Man Element); public abstract void VisitBoat(Boat Element); }
Visitor_B.cs(Vistor_A.cs)
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Visitor_B : Visitor { public override void VisitMan(Man Element) { Debug.Log("We right click on the Man!!!!"); } public override void VisitBoat(Boat Element) { Debug.Log("We right click on the Boat!!!!"); } }
抽象类Vistor派生出不同的访问者,访问者分别对类的不同对象分别处理逻辑
传参保证了可以引用到类的对象的属性
InputController.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; //处理鼠标输入点击 public class InputController : MonoBehaviour { Visitor visitor; void Accept(Visitor _visitor) { visitor = _visitor; } void Update() { //如果鼠标左键有点击 if (Input.GetMouseButtonDown(0)) { Accept(new Visitor_A()); Raycast(); } //如果鼠标右键键有点击 else if (Input.GetMouseButtonDown(1)) { Accept(new Visitor_B()); Raycast(); } } void Raycast() { .....//非核心代码 } }
根据不同情况实例对应的访问者,并传入给被访问者
Man.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Man : MonoBehaviour , IObjectAction{ ........//前略 public void Accept(Visitor _visitor) { _visitor.VisitMan(this); } }关于状态的传递,这里使用了“双分派”的技巧。首先InputController将访问者作为参数传递给了“人”类,完成第一次分派。然后“人”类调用作为参数的访问者的方法中的针对“人”类的方法——VisitMan,并将自己作为参数传递进去,完成第二次分派。结果是访问者和被访问者在这之后可以相互引用了