目錄 一、現實應用場景 二、初步實現 三、觀察者模式 3.1 應用場景 3.2 詳解 3.3 實現 3.4 設計類圖 四、實現 五、更多
一、現實應用場景
教師的手機號改變之后要通知給所有學生 如果有一個學生沒有通知到位就會產生遺漏 如何自動完成
二、初步實現
2.1 實現方案1
定義學生和教師類 教師類設置set和get方法 教師的手機號修改后要依次調用所有學生的類重新設置
# include <iostream> class Student
{
private : std:: string m_name; std:: string m_tPhone; public : Student ( const std:: string& name) { m_name = name; } void setTPhoneNubmer ( const std:: string& phone) { m_tPhone = phone; } void show ( ) { std:: cout << "Name: " << m_name << " Teacher's Phone: " << m_tPhone << std:: endl; }
} ; class Teacher
{
private : std:: string m_phone; public : Teacher ( const std:: string& phone) { m_phone = phone; } void setPhone ( const std:: string& phone) { m_phone = phone; } std:: string getPhone ( ) const { return m_phone; }
} ; int main ( )
{ Teacher zwz ( "12345" ) ; Student li ( "LiLei" ) ; Student Jie ( "Jie" ) ; Student wcz ( "wcz" ) ; li. setTPhoneNubmer ( zwz. getPhone ( ) ) ; Jie. setTPhoneNubmer ( zwz. getPhone ( ) ) ; wcz. setTPhoneNubmer ( zwz. getPhone ( ) ) ; li. show ( ) ; Jie. show ( ) ; wcz. show ( ) ; zwz. setPhone ( "67890" ) ; li. setTPhoneNubmer ( zwz. getPhone ( ) ) ; Jie. setTPhoneNubmer ( zwz. getPhone ( ) ) ; wcz. setTPhoneNubmer ( zwz. getPhone ( ) ) ; li. show ( ) ; Jie. show ( ) ; wcz. show ( ) ; return 0 ;
}
2.2 實現方案2
學生類中擁有一個教師的實例,該實例由外部傳入 只要教師的手機號在外部修改,那個學生類中只需要通過getPhone()
函數即可得到教師的手機號 實現過程如下
# include <iostream> class Teacher
{
private : std:: string m_phone; public : Teacher ( const std:: string& phone) { m_phone = phone; } void setPhone ( const std:: string& phone) { m_phone = phone; } std:: string getPhone ( ) const { return m_phone; }
} ; class Student
{
private : std:: string m_name; std:: string m_tPhone; const Teacher* m_teacher; public : Student ( const std:: string& name, const Teacher* teacher) { m_name = name; m_teacher = teacher; } void show ( ) { std:: cout << "Name: " << m_name << " Teacher's Phone: " << m_teacher-> getPhone ( ) << std:: endl; }
} ; int main ( )
{ Teacher zwz ( "12345" ) ; Student li ( "LiLei" , & zwz) ; Student Jie ( "Jie" , & zwz) ; Student wcz ( "wcz" , & zwz) ; li. show ( ) ; Jie. show ( ) ; wcz. show ( ) ; zwz. setPhone ( "67890" ) ; li. show ( ) ; Jie. show ( ) ; wcz. show ( ) ; return 0 ;
}
存在問題 兩個對象間存在緊耦合關系 如果換老師之后,老師的實例還得修改 缺少擴展性與靈活性
三、觀察者模式
3.1 應用場景
當對象發生變化,通知給其他對象
,需要其他對象做出調整 應用程序的可維護性和重用性較高
互動關系不能體現成類之間的直接調用,對象之間關系的解耦
3.2 詳解
觀察者模式又稱為發布訂閱模式 兩個角色 : 觀察者和被觀察對象兩者之間存在”觀察“的邏輯關聯 當被觀察者發生改變的時候,觀察者就會觀察到這樣的變化,并且做出相應的響應 觀察不是直接調用 實現觀察者模式有很多形式,比較直觀的一種是注冊-> 通知 -> 撤銷注冊 形式。
3.3 實現
步驟1:觀察者將自己注冊到被觀察對象中,被觀察對象將觀察者存放在一個容器中。 步驟2:被觀察者對象發生了某種變化,從容器中得到所有注冊過的觀察者,將變化通知觀察者。 步驟3(可選):觀察者告訴被觀察者要撤銷觀察,被觀察者從容器中將觀察者去除。
3.4 設計類圖
ConcreteSubject
: 主題對象,被觀察者,對應老師。 他有變化時通知ConcreteObserver
類的實例(學生)。學生根據變化自動調用update()
做出響應。 內部有一個隊列存儲、移除觀察者 當狀態發生變化時可以調用notifyObservers()
通知觀察者 將ConcreteSubject
與ConcreteObserver
類解耦 學生不只可以觀察老師,還可以觀察學院、某個同學等。 兩個類分別向上抽取了被觀察者接口 (Subject)
和觀察者接口(Observer)
。
四、實現
# include <iostream>
# include <list> class IObserver
{
public : virtual void update ( void * o) = 0 ;
} ; class ISubject
{
public : virtual void registerObserver ( IObserver* obj) = 0 ; virtual void removeObserver ( IObserver* obj) = 0 ; virtual void notifyObserver ( ) = 0 ;
} ; class Teacher : ISubject
{
private : std:: string m_phone; std:: list< IObserver* > m_subject; public : void setPhone ( const std:: string& phone) { m_phone = phone; notifyObserver ( ) ; } std:: string getPhone ( ) const { return m_phone; } void registerObserver ( IObserver* o) { m_subject. push_back ( o) ; } void removeObserver ( IObserver* o) { m_subject. remove ( o) ; } void notifyObserver ( ) { for ( auto item : m_subject) { item-> update ( ( void * ) m_phone. c_str ( ) ) ; } }
} ; class Student : public IObserver
{
private : std:: string m_name; std:: string m_tPhone; public : Student ( const std:: string& name) { m_name = name; } void update ( void * o) { m_tPhone = reinterpret_cast < char * > ( o) ; } void show ( ) { std:: cout << "Name: " << m_name << " Teacher's Phone: " << m_tPhone << std:: endl; }
} ; int main ( )
{ Teacher zwz; Student li ( "LiLei" ) ; Student Jie ( "Jie" ) ; Student wcz ( "wcz" ) ; Student test ( "test" ) ; zwz. registerObserver ( & li) ; zwz. registerObserver ( & Jie) ; zwz. registerObserver ( & wcz) ; std:: cout << "\n*******設置教師手機號為12345*******" << std:: endl; zwz. setPhone ( "12345" ) ; li. show ( ) ; Jie. show ( ) ; wcz. show ( ) ; zwz. removeObserver ( & wcz) ; std:: cout << "\n*******對教師手機號進行修改為67890*******" << std:: endl; zwz. setPhone ( "67890" ) ; li. show ( ) ; Jie. show ( ) ; std:: cout << "\n*******不會被改變*******" << std:: endl; wcz. show ( ) ; return 0 ;
}
創建觀察者接口IObserver()
,并規定了更新的行為。 創建被觀察者接口ISubject()
,并規定了添加、移除和通知觀察者的行為。 運行結果
五、更多
這個例子中需要在main
函數中手動調用注冊,可以在Observer
對象創建時傳入Subject
對象,以便自動注冊。 詳情請參閱 https://gitee.com/piglittle/design_patterns中的 Head_First_Design_Partterns
解決方案下的 observer_pattern
項目 其詳細的類圖如下