目錄
一.觀察者模式
觀察者(Observer)模式的定義:指多個對象間存在一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。這種模式有時又稱作發佈-訂閱模式、模型-視圖模式,它是對象行爲型模式。
意圖:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。
主要解決:一個對象狀態改變給其他對象通知的問題,而且要考慮到易用和低耦合,保證高度的協作。
何時使用:一個對象(目標對象)的狀態發生改變,所有的依賴對象(觀察者對象)都將得到通知,進行廣播通知。
如何解決:使用面向對象技術,可以將這種依賴關係弱化。
關鍵代碼:在抽象類裏有一個 ArrayList 存放觀察者們。
應用實例:假設現在有一名男子懷疑自己被戴了綠帽子,但是他又沒有證據,於是他花錢僱傭了一位私家偵探去調查他的老婆,並告訴這位私家偵探如果一有什麼動靜發生,就立馬通知他,好讓他採取行動。在這個例子中這位男子就是監聽者,而這位私家偵探就是觀察者,觀察者所要做的事情就是觀察某一事件是否發生,如果事件發生了就去通知監聽者,而監聽者所要做的就是處理事件。
觀察者和監聽者之間的關係(多對多):
- 多個觀察者可以爲同一個監聽者服務。
- 一個觀察者可以爲多個監聽者服務。
二.代碼實現
#include<iostream>
#include<map>
#include<vector>
class Listener
{
public:
Listener(std::string name)
:mname(name) {}
virtual void handleMessage(int message) = 0;
protected:
std::string mname;
};
class Listener1 : public Listener
{
public:
Listener1(std::string name) :Listener(name) {}
void handleMessage(int message)
{
switch (message)
{
case 1:
std::cout << mname << " : 1 " << "has been solved! " << std::endl;
break;
case 2:
std::cout << mname << " : 2 " << "has been solved! " << std::endl;
break;
default:
std::cout << mname << " no interested this message!" << std::endl;
break;
}
}
};
class Listener2 : public Listener
{
public:
Listener2(std::string name) :Listener(name) {}
void handleMessage(int message)
{
switch (message)
{
case 2:
std::cout << mname << " : 2 " << "has been solved! " << std::endl;
break;
case 3:
std::cout << mname << " : 3 " << "has been solved! " << std::endl;
break;
default:
std::cout << mname << " no interested this message!" << std::endl;
break;
}
}
};
class Listener3 : public Listener
{
public:
Listener3(std::string name) :Listener(name) {}
void handleMessage(int message)
{
switch (message)
{
case 1:
std::cout << mname << " : 1 " << "has been solved! " << std::endl;
break;
case 3:
std::cout << mname << " : 3 " << "has been solved! " << std::endl;
break;
default:
std::cout << mname << " no interested this message!" << std::endl;
break;
}
}
};
class Oberseve
{
public:
void notify(int message)//某一事件發生;
{
std::map<int, std::vector<Listener*>>::iterator fit = mymap.find(message);
if (fit != mymap.end())//有感興趣的監聽者
{
std::vector<Listener*>::iterator it = fit->second.begin();//vector迭代器
while (it != fit->second.end())
{
//消息通知 調用對方的接口
(*it)->handleMessage(message);
it++;
}
}
else//沒感興趣的監聽者
{
std::cout << "no listener interested this message!" << std::endl;
}
}
void registerMessage(int message, Listener* pl)//讓觀察者觀察某一事件
{
std::map<int, std::vector<Listener*>>::iterator fit = mymap.find(message);
if (fit != mymap.end())//找到了 該事件已經註冊 插入監聽者集合
{
fit->second.push_back(pl);
}
else//沒找到 map 插入一個關係
{
std::vector<Listener*> vec;
vec.push_back(pl);
mymap[message] = vec;
}
}
private:
std::map<int, std::vector<Listener*>> mymap;//事件 監聽者
};
int main()
{
Listener1 l1("listener1");
Listener2 l2("listener2");
Listener3 l3("listener3");
Oberseve ob;
ob.registerMessage(1, &l1);//表示1號監聽者對1號事件感興趣
ob.registerMessage(2, &l1);//表示2號監聽者對1號事件感興趣
ob.registerMessage(2, &l2);//表示2號監聽者對2號事件感興趣
ob.registerMessage(3, &l2);//表示3號監聽者對2號事件感興趣
ob.registerMessage(1, &l3);//表示1號監聽者對3號事件感興趣
ob.registerMessage(3, &l3);//表示3號監聽者對3號事件感興趣
ob.notify(1);//事件1發生
ob.notify(2);//事件2發生
ob.notify(3);//事件3發生
ob.notify(4);//事件4發生
return 0;
}
在上述代碼中,Listener類中的handleMessage(int message)函數,代表處理事件函數,即此時某監聽者感興趣的事件message發生了,監聽者會調用這個函數來進行相應的處理。在本例中,我們規定一號監聽者listener1只對事件1和事件2感興趣,二號監聽者只對事件2和事件3感興趣,三號監聽者只對事件1和事件3感興趣。
前面我們講到過一個監聽者可能對多個事件感興趣,爲了描述這一特徵,我們使用單映射容器map來存放某一事件和對這一事件感興趣的監聽者,我們用map容器中的鍵(key)來表示某一事件,用值(value)來表示對這一事件感興趣的監聽者,考慮到監聽者可能有多個,我們在用vector容器來存放對某一事件感興趣的監聽者,即這裏map容器中的鍵值對爲key:int->value:vector,而vector中存放監聽者,即
std::map<int, std::vector<Listener*>> mymap};//事件 監聽者
在觀察者類Oberseve中有兩個成員函數,分別是void notify(int message) 和 void registerMessage(int message, Listener* pl)。我們首先來看
void notify(int message)//某一事件發生;
{
std::map<int, std::vector<Listener*>>::iterator fit = mymap.find(message);
if (fit != mymap.end())//有感興趣的監聽者
{
std::vector<Listener*>::iterator it = fit->second.begin();//vector迭代器
while (it != fit->second.end())
{
//消息通知 調用對方的接口
(*it)->handleMessage(message);
it++;
}
}
else//沒感興趣的監聽者
{
std::cout << "no listener interested this message!" << std::endl;
}
}
這個函數代表此時message這個事件發生了,這是觀察者要乾的第一件事就是判斷是否有監聽者對此時發生的這個事件message感興趣,於是我們首先使用find函數在map容器中查找是否有鍵(key)== message的數據。如果有,說明有對這個事件感興趣的觀察者,接着我們就對這個事件感興趣的所有監聽者發送信息(因爲對 某一事件感興趣的監聽者可能有多個),也就是調用handleMessage這個藉口。如果沒有對這個事件感興趣的監聽者(即map容器中不存在鍵(key)== message 的數據),就不做任何處理。
void registerMessage(int message, Listener* pl)//讓觀察者觀察某一事件
{
std::map<int, std::vector<Listener*>>::iterator fit = mymap.find(message);
if (fit != mymap.end())//找到了 該事件已經註冊 插入監聽者集合
{
fit->second.push_back(pl);
}
else//沒找到 map 插入一個關係
{
std::vector<Listener*> vec;
vec.push_back(pl);
mymap[message] = vec;
}
}
registerMessage這個函數代表讓觀察者觀察某一事件,並且表明哪些監聽者對這個事件感興趣,假設現在我們給定了某一事件message,我們首先要做的就是判斷觀察者是否已經觀察了這個事件,即判斷當map容器中是否存在鍵(key) == message 的數據,如果不存在就將這個事件插入。如果存在就說明觀察者已經觀察了這一事件,即map容器中已經存在鍵(key) == message 的數據,那麼就將其他對這個事件感興趣的監聽者插入(因爲可能有多個監聽者對同一事件感興趣的可能)。