设计模式--观察者模式(KVO)
观察者模式(Observer):观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。
观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。在刚才的例子中,业务数据是被观察对象,用户界面是观察者。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。如果在用户界面、业务数据之间使用这样的观察过程,可以确保界面和数据之间划清界限,假定应用程序的需求发生变化,需要修改界面的表现,只需要重新构建一个用户界面,业务数据不需要发生变化。
观察者
被观察者
C++实现demo。
游戏中玩家数据和界面玩家UI之间必然会有关联,当玩家数据变化后,响应的UI也应该及时更新。
两个虚基类:AbsSubject(被观察者),AbsObserver(观察者); 被观察者实现类:User(玩家数据类);
观察者实现类:UserView(玩家信息面板类);HallView(大厅信息面板类)
玩家信息面板和大厅信息面板都包含玩家昵称(name)和金币值(gold),当玩家金币值发生变化后,玩家(User)通知面板(UserView和HallView)也应发生响应变化。
AbsSubject.h(被观察者):
1 class AbsObserver; 2 //被观察者,虚基类 3 class AbsSubject 4 { 5 public: 6 //ctor 7 AbsSubject():m_bChanged(false) {}; 8 //pure dtor 9 virtual ~AbsSubject() { removeAllObserver(); }; 10 //注册观察者 11 void addObserver(AbsObserver* obser); 12 //注销观察者 13 void removeObserver(AbsObserver* obser); 14 //注销所有观察者 15 void removeAllObserver(); 16 //向所有观察者发送通知 17 void postNotification(void*arg = NULL); 18 19 //get observer count 20 int getObserverCount() { return m_setObser.size(); } 21 //状态是否变化 22 bool hasChanged() { return m_bChanged; }; 23 //set changed true 24 void setChanged() { m_bChanged = true; } 25 //clear changed 26 void clearChanged() { m_bChanged = false; } 27 28 29 private: 30 bool m_bChanged;//是否变化 31 set<AbsObserver*> m_setObser;//观察者集合,set保证对象唯一 32 };
AbsSubject.cpp(被观察者):
1 #include "stdafx.h" 2 #include "AbsSubject.h" 3 4 5 6 void AbsSubject::addObserver(AbsObserver * obser) 7 { 8 if (!obser)return; 9 m_setObser.insert(obser); 10 } 11 12 void AbsSubject::removeObserver(AbsObserver * obser) 13 { 14 if (!obser)return; 15 m_setObser.erase(obser); 16 } 17 18 void AbsSubject::removeAllObserver() 19 { 20 m_setObser.clear(); 21 } 22 23 void AbsSubject::postNotification(void * arg) 24 { 25 if (!hasChanged())return; 26 clearChanged(); 27 if (getObserverCount() == 0)return;//safe check 28 29 set<AbsObserver*>::iterator itor = m_setObser.begin(); 30 do 31 { 32 (*itor)->update(this, arg); 33 itor++; 34 } while (itor != m_setObser.end()); 35 36 }
AbsObserver(观察者):
1 class AbsSubject; 2 //观察者基类,纯虚基类 3 class AbsObserver 4 { 5 public: 6 //ctor 7 AbsObserver() {}; 8 //dtor 9 virtual ~AbsObserver() {}; 10 //pure virtual function. 11 //当被观察者(subject)发生变化时,通知调用该方法 12 virtual void update(AbsSubject* subject, void* arg) = 0; 13 14 };
被观察者实现类:User(玩家数据类)
1 #pragma once 2 3 //玩家数据,被观察者 4 class User:public AbsSubject 5 { 6 public: 7 //ctor 8 User(string name); 9 //dtor 10 ~User(); 11 12 //增加gold 13 void addGold(int gold); 14 15 //广播通知 16 void post(const string& content); 17 18 public: 19 //get name 20 string getName() { return m_strName; } 21 //get gold; 22 int getGold() { return m_iGold; } 23 24 private: 25 string m_strName;//昵称 26 int m_iGold;//金币 27 28 }; 29 30 31 32 User::User(string name) 33 :m_strName(name), 34 m_iGold(100) 35 { 36 } 37 38 39 User::~User() 40 { 41 } 42 43 void User::addGold(int gold) 44 { 45 if (gold == 0)return; 46 m_iGold += gold; 47 m_iGold = m_iGold < 0 ? 0 : m_iGold;//safe check 48 49 post(m_strName); 50 } 51 52 void User::post(const string & content) 53 { 54 setChanged(); 55 postNotification(const_cast<char*>(content.c_str())); 56 57 }
观察者实现类:UserView(玩家信息面板类):
1 #pragma once 2 3 //玩家界面,观察者 4 class UserView:public AbsObserver 5 { 6 public: 7 //ctor 8 UserView(User* user) :m_user(user){ user->addObserver(this); } 9 //dtor 10 ~UserView() { m_user->removeObserver(this); } 11 //当被观察者(subject)发生变化时,通知调用该方法 12 virtual void update(AbsSubject* subject, void* arg); 13 14 private: 15 //string m_strName;//user name 16 User* m_user;//user 17 }; 18 19 void UserView::update(AbsSubject * subject, void * arg) 20 { 21 char* content = static_cast<char*>(arg); 22 if (dynamic_cast<User*>(subject)) 23 { 24 cout << "UserView::update From User=" << m_user->getName() << ",gold=" << m_user->getGold() << ",Arg=" << content << endl; 25 } 26 else 27 { 28 cout << "UserView::update From XXX=" << m_user->getName() << ",gold=" << m_user->getGold() << ",Arg=" << content << endl; 29 } 30 }
HallView(大厅信息面板类):
1 #pragma once 2 //大厅界面,观察者 3 class HallView:public AbsObserver 4 { 5 public: 6 //ctor 7 HallView(User* user):m_user(user) { user->addObserver(this); } 8 //dtor 9 ~HallView() { m_user->removeObserver(this); }; 10 //当被观察者(subject)发生变化时,通知调用该方法 11 virtual void update(AbsSubject* subject, void* arg); 12 13 private: 14 User* m_user;//玩家 15 16 }; 17 18 void HallView::update(AbsSubject * subject, void * arg) 19 { 20 char* content = static_cast<char*>(arg); 21 if (dynamic_cast<User*>(subject)) 22 { 23 cout << "HallView::update From User="<<m_user->getName()<<",gold=" << m_user->getGold()<<",arg="<<content<< endl; 24 } 25 else 26 { 27 cout << "HallView::update From XXX=" << m_user->getName() << ",gold=" << m_user->getGold()<<",arg=" << content << endl; 28 } 29 }
main()测试:
1 int main() 2 { 3 //玩家(被观察者) 4 User* user = new User("孟栋"); 5 6 //玩家面板(观察者1) 7 UserView* userView = new UserView(user); 8 //大厅面板(观察者2) 9 HallView* hallView = new HallView(user); 10 11 12 13 //玩家增加50金币,玩家面板和大厅面板会更新玩家UI信息 14 user->addGold(50); 15 16 //玩家减少30金币,玩家面板和大厅面板会更新玩家UI信息 17 user->addGold(-30); 18 19 return 0; 20 }
打印:
UserView::update From User=孟栋,gold=150,Arg=孟栋 HallView::update From User=孟栋,gold=150,arg=孟栋 UserView::update From User=孟栋,gold=120,Arg=孟栋 HallView::update From User=孟栋,gold=120,arg=孟栋
多加点评!谢谢