实现复杂的任务通常一系列相互协作的类。为了达到此目的,对象A为了调用对象B的方法,就必须知道对象B的存在和其接口。最简单的方法是让A.cpp包含B.h,然后直接调用B类的方法。这样做的副作用:引入了A和B的编译时依赖,为了维持一致性而使各类紧耦合(tightly coupled)。结果是,类A的通用性减弱了,因为其他系统不引入类B就不能重用A。另外,编译时紧耦合会导致用户不能在运行时给系统动态添加新的依赖。
MVC架构
模型/视图/控制器(Model/View/Controller),MVC包括三类对象,模型Model是应用对象,视图View是它在屏幕上的表示,控制器Controller定义用户界面对用户输入的响应方式。MVC模式要求业务逻辑(Model,模型) 独立于用户界面(View,视图),
MVC通过建立一个“订购/通知”协议来分离视图和模型。视图必须保证它的显示正确地反映了模型的状态。一旦模型的数据发生变化,模型将通知有关的视图,每个视图相应地得到刷新自己的机会。这种做法的好处是:可以为一个模型提供不同的多个视图表达形式,也能够为一个模型创建新的视图而无须重写模型。
OBSERVER(观察者)----对象行为型模式
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
在真实的应用程序中,通常需要通过更新视图来反映底层模型的其他变化。因为改变模型的某个方面可能引起其他具有依赖关系的模型的状态改变。这就要求模型代码在状态改变时通知视图层。
实现观察者模式的做法就是引入两个概念:subject(主题)和Observer(观察者)。一个或多个观察者注册主题中感兴趣的事件,之后主题会在自身状态发生变化时通知所有注册的观察者。下图定义了 应用数据的类和负责界面表示的类。表格对象和棒状图对象都依赖于数据对象,因此数据对象的任何状态改变都应立即通知它们。同时也没有理由将依赖于该数据对象的对象的数目限定为两个。再重复一遍含义,也就是说,一个主题(或者叫做目标)可以有任意数目的依赖它的观察者,一旦主题的状态发生改变,所有的观察者都得到通知。作为对这个通知的响应,每个观察者都将查询主题以使其改变的状态与目标的状态同步。这种交互也称之为发布——订阅(publish-subscribe)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#ifndef OBSERVER_H #define OBSERVER_H #include <map> #include <vector> /// An abstract interface for an observer class. //观察者:为那些在主体发生改变时须获得通知的对象定义一个更新接口 class IObserver { public: virtual ~IObserver() {} virtual void Update(int message) = 0; }; //主题: 主题知道它的观察者,提供注册和删除观察者对象的接口。 class ISubject{ public: ISubject(); virtual ~ISubject(); /// Add a new observer to the list of observers. virtual void Subscribe(int message, IObserver *observer); /// Remove an existing observer from the list of observers. virtual void Unsubscribe(int message, IObserver *observer); /// Call the Update() method of all subscribed observers. virtual void Notify(int message); private: typedef std::vector<IObserver *> ObserverList; typedef std::map<int, ObserverList> ObserverMap; ObserverMap mObservers; }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include "stdafx.h" #include "observer.h" ISubject::ISubject() {} ISubject::~ISubject() {} void ISubject::Subscribe(int message, IObserver *observer){ if (observer){ ObserverMap::iterator it = mObservers.find(message); if (it == mObservers.end()){ mObservers[message] = ObserverList();//创建一个列表,将每个消息的订阅者放入其中 } mObservers[message].push_back(observer); } } void ISubject::Unsubscribe(int message, IObserver *observer){ ObserverMap::iterator it = mObservers.find(message); if (it != mObservers.end()){ ObserverList &list = mObservers[message]; ObserverList::iterator li; //感觉这部分代码有BUG啊,如果我取消订阅 for (li = list.begin(); li != list.end();){ if ((*li) == observer){ list.erase(li); } else{ ++li; } } } } void ISubject::Notify(int message){ ObserverMap::iterator it = mObservers.find(message); if (it != mObservers.end()){ ObserverList &list = mObservers[message]; ObserverList::iterator li; for (li = list.begin(); li != list.end(); ++li){ (*li)->Update(message); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#ifndef SUBJECT_H #define SUBJECT_H #include "observer.h" /// A concrete subject class, based on the ISubject interface. class MySubject : public ISubject { public: enum Messages { ADD, REMOVE, UPDATE }; }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include "subject.h" #include <iostream> #include <string> using std::cout; using std::endl; /// An observer class that wishes to receive a notification class MyObserver : public IObserver{ public: MyObserver(const std::string &str) : mName(str) {} void Update(int message){ cout << mName << " Received message " << message << endl; } private: std::string mName; }; int main(int, char **){ // create three observer classes MyObserver observer1("observer1"); MyObserver observer2("observer2"); MyObserver observer3("observer3"); // create a single subject class MySubject subject; // each observer registers interest for specific // messages that the subject can issue subject.Subscribe(MySubject::ADD, &observer1); subject.Subscribe(MySubject::ADD, &observer2); subject.Subscribe(MySubject::REMOVE, &observer2); subject.Subscribe(MySubject::UPDATE, &observer1); subject.Subscribe(MySubject::UPDATE, &observer3); // make the subject issue ADD and UPDATE messages cout << "Notify ADD:" << endl; subject.Notify(MySubject::ADD); cout << "Notify UPDATE:" << endl; subject.Notify(MySubject::UPDATE); return 0; } |
创建了3个独立的观察者类,它们分别订阅了MySubject类定义的两个消息的不同组合。
在调用suject.Notify()后,主题会遍历已经订阅过此指定消息的观察者列表并为其中的每一个观察者调用Update()方法。
1 2 3 4 5 6 7 8 9 10 11 |
void ISubject::Notify(int message){ ObserverMap::iterator it = mObservers.find(message);//迭代器指向列表字典 if (it != mObservers.end()){ ////找到某个特定消息的那个list,typedef std::vector<IObserver *> ObserverList; ObserverList &list = mObservers[message]; ObserverList::iterator li; for (li = list.begin(); li != list.end(); ++li){ (*li)->Update(message);//动态调用Update函数 } } } |
注意:MySubject类对MyObject类没有编译时依赖关系。这两个类的关系实在运行时动态创建的。带来的性能损耗就是,在函数调用之前遍历观察者列表的开销。同时,在销毁观察者对象之前,必须先取消订阅观察者对象,否则如果对象已经销毁了还给它通知会导致应用崩溃。
结果: