设计模式之观察者模式(Observer)
发表于2018-10-25
还是《Game.Programming.Patterns》一书中对观察者模式的个人理解,惯例看一下菜鸟教程的描述:
观察者模式应用的也比较多了,各大框架中的消息/通知/事件(叫法多样),很多就是用的观察者模式,或者在此基础上结合多种设计模式 ··· ···
实现:玩家在桥上失足掉入河中,达成成就~ (233333)
public enum ActorEvent { fellOffBridge, }
//角色基类 public class Actor { }
//观察者基类(通知/消息/事件) public abstract class Observer { //接收通知 public abstract void OnNotify(Actor actor, ActorEvent actorEvent); }
//观察者链表节点 public class ObserverNode { //下一节点 public ObserverNode next; //节点对应的观察者 public Observer observer { get; private set; } //构造函数 public ObserverNode(Observer relatedOnserver) { observer = relatedOnserver; next = null; } }
//被观察者基类 public class Subject { ////改进前 ////观察者列表 //被观察者需要保存所有的观察者, 不论采用哪种数据结构, 增删观察者需要分配内存 //List<Observer> observerList = new List<Observer>(); ////初次改进 ////改用链式结构, 由观察者自己记录, 观察者的多少无太大影响, 无需动态内存 ////这样的方式也有缺点! 一个被观察者 可以有多个观察者, 但一个观察者 只能有一个被观察对象, 不能同时对应多个观察者, 类似于线性结构 //protected Observer observer; //再次改进 //记录观察者节点, 而不是记录和观察者, 不同的被观察者有不同的节点, 不同节点可以指向同一个观察者, 类似于网状结构 protected ObserverNode head; public Subject() { head = null; } //添加观察者节点, 将其插入到链表的首位, 这样被观察者依次给观察者通知时, 会与添加顺序相反 //如果将新加项添加到链表末位, 需要遍历整个链表直到最末位, 效率相对较慢 //如果各个观察者之间不存在耦合, 通知的先后顺序不会发生任何影响 public void AddObserver(ObserverNode node) { node.next = head; head = node; } //删除观察者节点, 删除操作需要遍历整个链表, 显然这种操作不够优雅, 可以尝试双向链表~ public void DeleteObserver(ObserverNode node) { //如果要删除项在首位, head指向下一个, 删除首位next引用 if (head == node) { head = node.next; node.next = null; return; } //如果要删除项不在首位, 遍历链表 ObserverNode curNode = head; while (curNode != null) { //剔除当前项, 将上一个的引用指向下一个 if (curNode.next == node) { curNode.next = node.next; node.next = null; return; } curNode = curNode.next; } } //删除所有观察者节点 ////除了循环删除引用, 还可以定义一条特定的Notify通知, 需要删除是通知观察者, 观察者自行注销 public void DeleteAllObserver() { //遍历删除所有节点的next ObserverNode curNode = head; while (curNode.next != null) { head = curNode.next; curNode.next = null; curNode = head; } head = null; } //通知观察者 protected void Notify(Actor actor, ActorEvent actorEvent) { //遍历所有节点, 调用节点的观察者接收函数 ObserverNode curNode = head; while (curNode != null) { curNode.observer.OnNotify(actor, actorEvent); curNode = curNode.next; } } }
//成就, 观察者 public class Achievements { public void OnNotify(Actor actor, ActorEvent actorEvent) { if (IsHero(actor)) UnLock(actorEvent); } void UnLock(ActorEvent actorEvent) { } bool IsHero(Actor actor) { return true; } }
//物理系统, 被观察者 public class Physics : Subject { Actor player = new Actor(); void UpdateMovement() { if (true) Notify(player, ActorEvent.fellOffBridge); } }