专业建设网站公司哪家好,建设工程合同管理多少分及格,对二次网站开发的认识,网站建设工具的种类定义
观察者模式定义了对象间的一种一对多的依赖关系#xff0c;当一个对象的状态发生改变时#xff0c;所有依赖于它的对象都得到通知并被自动更新。
这是定义#xff0c;看不懂就看不懂吧#xff0c;我接下来举个例子慢慢说
为什么我们需要观察者模式
我们看一个很简…定义
观察者模式定义了对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖于它的对象都得到通知并被自动更新。
这是定义看不懂就看不懂吧我接下来举个例子慢慢说
为什么我们需要观察者模式
我们看一个很简单的需求现在要你在游戏中加入成就系统在物体坠落1000米的时候给玩家发一个成就勋章你要这么做
最直观的方法就是在游戏的物理系统那一部分中加入这么一段代码
void Physics::updateEntity(Entity entity)
{bool wasOnSurface entity.isOnSurface();entity.accelerate(GRAVITY);entity.update();if (wasOnSurface !entity.isOnSurface()){if (surface.height - entity.height 1000){//解锁成就unlockFallOffBridge();}}
}咋一看是不是还行就加了几行而已。 那么如果我还要求你播放坠落音效呢是不是还得这样写
void Physics::updateEntity(Entity entity)
{bool wasOnSurface entity.isOnSurface();entity.accelerate(GRAVITY);entity.update();if (wasOnSurface !entity.isOnSurface()){if (surface.height - entity.height 1000){//解锁成就unlockFallOffBridge();//播放音效playfallmusic();}}
}这样看也还行那如果组长让你根据物体撞击不同的地面播放不同的地面音效那这段代码是不是又得膨胀了
void Physics::updateEntity(Entity entity)
{bool wasOnSurface entity.isOnSurface();entity.accelerate(GRAVITY);entity.update();if (wasOnSurface !entity.isOnSurface()){if (surface.height - entity.height 1000){//解锁成就unlockFallOffBridge();//播放音效if (hitground){playhitgroundmusic();}if (hitwater){playhitwatermusic();}//.....}}
}要知道这可是在你的游戏的物理引擎中我们并不想看到在处理撞击代码的线性代数时 有出现关于成就系统音效系统的调用是不我们喜欢的是照旧让关注游戏一部分的所有代码集成到一块。我们想要解耦物理系统和这些不相关的东西。
这就是观察者模式出现的原因。 这让代码宣称有趣的事情发生了而不必关心到底是谁接受了通知。
一旦你使用了观察者模式你的代码就会变成这样
void Physics::updateEntity(Entity entity)
{bool wasOnSurface entity.isOnSurface();entity.accelerate(GRAVITY);entity.update();if (wasOnSurface !entity.isOnSurface()){notify(entity, EVENT_START_FALL);}
}是不是简洁了很多很多比刚才那一大堆丑陋的代码好看多了。
观察者模式做的就是声称“额我不知道有谁感兴趣但是这个东西刚刚掉下去了。做你想做的事吧。”
可能有人会说诶这也没有完全解耦啊。的确物理引擎确实决定了要发送什么通知所以这并没有完全解耦。但在架构这个领域通常只能让系统变得更好而不是完美。
如何构建观察者模式
最传统的构建方式就是这样使用对象模式构建观察者
我们先写一个基础的观察者抽象基类
class Observer
{
public:virtual ~Observer() {}virtual void onNotify(const Entity entity, Event event) 0;
};然后让我们的成就系统和音效系统等想成为观察者的系统都继承这个基类
class Achievements : public Observer
{
public:virtual void onNotify(const Entity entity, Event event){switch (event){case EVENT_ENTITY_FELL:if (entity.isHero() heroIsOnBridge_){unlock(ACHIEVEMENT_FELL_OFF_BRIDGE);}break;// 处理其他事件更新heroIsOnBridge_变量……}}private:void unlock(Achievement achievement){// 如果还没有解锁那就解锁成就……}bool heroIsOnBridge_;
};对于被观察者如物理系统中我们只要让它持有这个observer的指针就好了一旦出现了某些事件我们就给这些指针指向的observer发消息。 为了正式一点让所有可能的系统都成为被观察者我们写一个叫subject的基类让所有想成为被观察者的系统都可以继承这个基类来成为被观察者。
class Subject
{
public:void addObserver(Observer* observer){// 添加到数组中……}void removeObserver(Observer* observer){// 从数组中移除……}void removeObserver(Observer* observer){// 从数组中移除……}
protected:void notify(const Entity entity, Event event){for (int i 0; i numObservers_; i){observers_[i]-onNotify(entity, event);}}private:Observer* observers_[MAX_OBSERVERS];int numObservers_
};我们可以看见这里写了一个观察者数组存了许多观察者的指针这是因为大部分情况下被观察者可能会有好多个观察者观察着它。然后我们也写了一些方法来增删这个数组。
然后就是面向对象的东西了我们让物理系统继承这个基类
class Physics : public Subject
{
public:void updateEntity(Entity entity);
};现在当物理引擎做了些值得关注的事情它调用notify()就像之前的例子。 它遍历了观察者列表通知所有观察者。 恭喜你已经掌握了如何写一个观察者模式你所看到的就是一个观察者模式的全部。现在来回顾一下定义
观察者模式定义了对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖于它的对象都得到通知并被自动更新。
是不是有点明白了
**
观察者模式的使用场合
**
当一个抽象模式有两个方面其中一个方面依赖于另一个方面需要将这两个方面分别封装到独立的对象中彼此独立地改变和复用的时候。 当一个系统中一个对象的改变需要同时改变其他对象内容但是又不知道待改变的对象到底有多少个的时候。 当一个对象的改变必须通知其他对象作出相应的变化但是不能确定通知的对象是谁的时候。
观察者模式的缺点
由于观察者模式调用了一些虚方法终究会比静态调用慢一些。观察者模式是同步的。 被观察者直接调用了观察者这意味着直到所有观察者的通知方法返回后 被观察者才会继续自己的工作。观察者会阻塞被观察者的运行。由于被观察者维护了一个数组来存储观察者指针在实际情况中一般会用动态数组而不是这次例子中的静态数组。这样就会做出太多的动态分配。解决方法还是有的那就是使用链表而不是数组来存储观察者指针反正你都得遍历发通知这俩差不多。
原文链接https://gpp.tkchu.me/observer.html