设计模式介绍
一、观察者模式
1. 观察者模式定义
定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
2. 观察者模式本质
观察者模式的本质:触发联动
3. 观察者模式结构和说明
(1) 结构
(2) 调用顺序
4. 观察者模式适用情况
- 当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化,那么就可以选用观察者模式,将这两者封装成观察者和目标对象,当目标对象变化的时候,依赖于它的观察者对象也会发生相应的变化。这样就把抽象模型的这两个方面分离开了,使得它们可以独立地改变和复用。
- 如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变,这种情况可以选用观察者模式,被更改的那一个对象很明显就相当于是目标对象,而需要连带修改的多个其他对象,就作为多个观察者对象了。
- 当一个对象必须通知其他的对象,但是你又希望这个对象和其他被它通知的对象是松散耦合的。也就是说这个对象其实不想知道具体被通知的对象。这种情况可以选用观察者模式,这个对象就相当于是目标对象,而被它通知的对象就是观察者对象了。
5. 观察者模式优缺点
(1) 优点
- 观察者模式实现了观察者和目标之间的抽象耦合
原本目标对象在状态发生改变的时候,需要直接调用所有的观察者对象,但是抽象出观察者接口以后,目标和观察者就只是在抽象层面上耦合了,也就是说目标只是知道观察者接口,并不知道具体的观察者的类,从而实现目标类和具体的观察者类之间解耦。 - 观察者模式实现了动态联动
所谓联动,就是做一个操作会引起其他相关的操作。由于观察者模式对观察者注册实行管理,那就可以在运行期间,通过动态地控制注册的观察者,来控制某个动作的联动范围,从而实现动态联动。 - 观察者模式支持广播通信
由于目标发送通知给观察者是面向所有注册的观察者,所以每次目标通知的信息就要对所有注册的观察者进行广播。当然,也可以通过在目标上添加新的功能来限制广播的范围。
在广播通信的时候要注意一个问题,就是相互广播造成死循环的问题。比如A和B两个对象互为观察者和目标对象,A对象发生状态变化,然后A来广播信息,B对象接收到通知后,在处理过程中,使得B对象的状态也发生了改变,然后B来广播信息,然后A对象接到通知后,又触发广播信息…,如此A引起B变化,B又引起A变化,从而一直相互广播信息,就造成死循环。
(2) 缺点
- 可能会引起无谓的操作
由于观察者模式每次都是广播通信,不管观察者需不需要,每个观察者都会被调用update方法,如果观察者不需要执行相应处理,那么这次操作就浪费了。其实浪费了还好,最怕引起误更新,那就麻烦了,比如,本应该在执行这次状态更新前把某个观察者删除掉,这样通知的时候就没有这个观察者了,但是现在忘掉了,那么就会引起误操作。
6. 相关模式
- 观察者模式和状态模式
观察者模式和状态模式是有相似之处的。
观察者模式是当目标状态发生改变时,触发并通知观察者,让观察者去执行相应的操作。而状态模式是根据不同的状态,选择不同的实现,这个实现类的主要功能就是针对状态相应地操作,它不像观察者,观察者本身还有很多其他的功能,接收通知并执行相应处理只是观察者的部分功能。
当然观察者模式和状态模式是可以结合使用的。观察者模式的重心在触发联动,但是到底决定哪些观察者会被联动,这时就可以采用状态模式来实现了,也可以采用策略模式来进行选择需要联动的观察者。 - 观察者模式和中介者模式
观察者模式和中介者模式是可以结合使用的。前面的例子中目标都只是简单地通知一下,然后让各个观察者自己去完成更新就结束了。如果观察者和被观察的目标之间的交互关系很复杂,比如,有一个
界面,里面有三个下拉列表组件,分别是选择国家、省份州、具体的城市,很明显这是一个三级联动,当你选择一个国家的时候,省份/州应该相应改变数据,省份/州一改变,具体的城市也需要改变。这种情况下,很明显需要相关的状态都联动准备好了,然后再一次性地通知观察者。也就是界面做更新处理,不会仅国家改变一下,省份和城市还没有改,就通知界面更新。这种情况就可以使用中介者模式来封装观察者和目标的关系
二、观察者模式示例代码
#include <iostream>
#include <string>
#include <list>
using namespace std;
//观察者模式拉模型实现
class BlogBase;
//观察者
class ObserverBase
{
public:
ObserverBase() = default;
virtual ~ObserverBase() = default;
virtual void Update(const BlogBase& blog) = 0;
};
//博客
class BlogBase
{
public:
BlogBase() = default;
virtual ~BlogBase() = default;
void Attach(ObserverBase *observer) { m_observers.push_back(observer); } //添加观察者
void Remove(ObserverBase *observer) { m_observers.remove(observer); } //移除观察者
void Notify(const BlogBase& blog) //通知观察者
{
auto iter = m_observers.begin();
for(; iter != m_observers.end(); iter++)
(*iter)->Update(blog);
}
virtual void SetStatus(string s) = 0; //设置状态
virtual string GetStatus() const= 0; //获得状态
private:
list<ObserverBase* > m_observers; //观察者链表
};
//具体博客类
class BlogCSDN : public BlogBase
{
private:
string m_name; //博主名称
public:
explicit BlogCSDN(string name): m_name(std::move(name)) {}
~BlogCSDN() override = default;
void SetStatus(string s) override { //具体设置状态信息
m_status = "CSDN:" + m_name + ":" + s;
Notify(*this);
}
string GetStatus() const override { return m_status; }
protected:
string m_status; //状态
};
//具体观察者
class ObserverBlogCSDN : public ObserverBase
{
private:
string m_name; //观察者名称
public:
ObserverBlogCSDN(string name): m_name(std::move(name)){}
~ObserverBlogCSDN() override = default;
void Update(const BlogBase& blog) override
{
cout<<m_name<<" observer->"<<blog.GetStatus()<<endl; //拉模型
}
};
int main(){
BlogBase *blog = new BlogCSDN("wangdaming");
ObserverBase *observer1 = new ObserverBlogCSDN("wangdaming");
blog->Attach(observer1);
blog->SetStatus("DesignMode");
blog->SetStatus("DataStruct");
blog->Remove(observer1);
delete blog;
delete observer1;
return 0;
}
#include <iostream>
#include <string>
#include <list>
using namespace std;
//观察者模式推模型实现
class BlogBase;
//观察者
class ObserverBase
{
public:
ObserverBase() = default;
virtual ~ObserverBase() = default;
virtual void Update(const std::string& status) = 0;
};
//博客
class BlogBase
{
public:
BlogBase() = default;
virtual ~BlogBase() = default;
void Attach(ObserverBase *observer) { m_observers.push_back(observer); } //添加观察者
void Remove(ObserverBase *observer) { m_observers.remove(observer); } //移除观察者
void Notify(const std::string& status) //通知观察者
{
auto iter = m_observers.begin();
for(; iter != m_observers.end(); iter++)
(*iter)->Update(status);
}
virtual void SetStatus(string s) = 0; //设置状态
virtual string GetStatus() const= 0; //获得状态
private:
list<ObserverBase* > m_observers; //观察者链表
};
//具体博客类
class BlogCSDN : public BlogBase
{
private:
string m_name; //博主名称
public:
explicit BlogCSDN(string name): m_name(std::move(name)) {}
~BlogCSDN() override = default;
void SetStatus(string s) override { //具体设置状态信息
m_status = "CSDN:" + m_name + ":" + s;
Notify(m_status);
}
string GetStatus() const override { return m_status; }
protected:
string m_status; //状态
};
//具体观察者
class ObserverBlogCSDN : public ObserverBase
{
private:
string m_name; //观察者名称
public:
ObserverBlogCSDN(string name): m_name(std::move(name)){}
~ObserverBlogCSDN() override = default;
void Update(const std::string& status) override
{
cout<<m_name<<" observer->"<<status<<endl; //推模型
}
};
int main(){
BlogBase *blog = new BlogCSDN("wangdaming");
ObserverBase *observer1 = new ObserverBlogCSDN("wangdaming");
blog->Attach(observer1);
blog->SetStatus("DesignMode");
blog->SetStatus("DataStruct");
blog->Remove(observer1);
delete blog;
delete observer1;
return 0;
}
#include <iostream>
#include <string>
#include <list>
using namespace std;
//动态触发联动:区别对待观察者
class BlogBase;
//观察者
class ObserverBase
{
public:
ObserverBase() = default;
virtual ~ObserverBase() = default;
virtual void Update(const BlogBase& blog) = 0;
virtual std::string GetName() = 0;
};
//博客
class BlogBase
{
public:
BlogBase() = default;
virtual ~BlogBase() = default;
void Attach(ObserverBase *observer) { m_observers.push_back(observer); } //添加观察者
void Remove(ObserverBase *observer) { m_observers.remove(observer); } //移除观察者
virtual void SetStatus(string s) = 0; //设置状态
virtual string GetStatus() const= 0; //获得状态
virtual void SetOp(string op) = 0; //设置操作
virtual string GetOp() const= 0; //获得操作
protected:
virtual void Notify(const BlogBase& blog) //通知观察者
{
auto iter = m_observers.begin();
for(; iter != m_observers.end(); iter++)
{
(*iter)->Update(blog);
}
}
protected:
list<ObserverBase* > m_observers; //观察者链表
};
//具体博客类
class BlogCSDN : public BlogBase
{
private:
string m_name; //博主名称
public:
explicit BlogCSDN(string name): m_name(std::move(name)) {}
~BlogCSDN() override = default;
void SetStatus(string s) override { //具体设置状态信息
m_status = "CSDN:" + m_name + ":" + s;
Notify(*this);
}
string GetStatus() const override { return m_status; }
void SetOp(string op) override { //具体设置状态信息
m_op = op;
}
string GetOp() const override { return m_op; }
protected:
void Notify(const BlogBase& blog) override //通知观察者
{
auto iter = m_observers.begin();
for(; iter != m_observers.end(); iter++)
{
std::string op = GetOp();
if(op == "modify" && (*iter)->GetName() == "wangdaming")
{
(*iter)->Update(blog);
}
if(op == "update" && (*iter)->GetName() == "others")
{
(*iter)->Update(blog);
}
}
}
protected:
string m_status ; //状态
string m_op ;//操作
};
//具体观察者
class ObserverBlogCSDN : public ObserverBase
{
public:
ObserverBlogCSDN(string name): m_name(std::move(name)){}
~ObserverBlogCSDN() override = default;
void Update(const BlogBase& blog) override
{
cout<<m_name<<" observer->"<<blog.GetStatus()<<":"<<blog.GetOp()<<endl; //拉模型
}
std::string GetName() override
{
return m_name;
}
private:
string m_name; //观察者名称
};
int main(){
BlogBase *blog = new BlogCSDN("wangdaming");
ObserverBase *observer1 = new ObserverBlogCSDN("wangdaming");
ObserverBase *observer2 = new ObserverBlogCSDN("others");
blog->Attach(observer1);
blog->Attach(observer2);
blog->SetOp("modify");
blog->SetStatus("DesignMode");
blog->SetOp("update");
blog->SetStatus("DataStruct");
blog->Remove(observer1);
blog->Remove(observer2);
delete blog;
delete observer1;
return 0;
}
#include <iostream>
#include <string>
#include <list>
#include <memory>
using namespace std;
//观察者模式拉模型实现
//采用weak_ptr方式实现观察者列表
//优点:观察者目标类能知道观察者列表中的对象是否有效
class BlogBase;
//观察者
class ObserverBase
{
public:
ObserverBase() = default;
virtual ~ObserverBase() = default;
virtual void Update(const BlogBase& blog) = 0;
};
//博客
class BlogBase
{
public:
BlogBase() = default;
virtual ~BlogBase() = default;
void Attach(std::weak_ptr<ObserverBase>&& observer) //添加观察者
{
m_observers.push_back(std::move(observer));
}
void Remove(const std::weak_ptr<ObserverBase>& observer) //移除观察者
{
m_observers.remove_if([&](const std::weak_ptr<ObserverBase>& item)->bool{
if(!item.expired())
{
return item.lock() == observer.lock();
}
return false;
});
}
void Notify(const BlogBase& blog) //通知观察者
{
auto iter = m_observers.begin();
for(; iter != m_observers.end();)
{
if(!iter->expired())
{
iter->lock()->Update(blog);
iter++;
} else{
std::cout<<"observer is null."<<std::endl;
iter = m_observers.erase(iter);
}
}
}
uint32_t Size(){return m_observers.size();}
virtual void SetStatus(string s) = 0; //设置状态
virtual string GetStatus() const= 0; //获得状态
private:
list<std::weak_ptr<ObserverBase>> m_observers; //观察者链表
};
//具体博客类
class BlogCSDN : public BlogBase
{
private:
string m_name; //博主名称
public:
explicit BlogCSDN(string name): m_name(std::move(name)) {}
~BlogCSDN() override = default;
void SetStatus(string s) override { //具体设置状态信息
m_status = "CSDN:" + m_name + ":" + s;
Notify(*this);
}
string GetStatus() const override { return m_status; }
protected:
string m_status; //状态
};
//具体观察者
class ObserverBlogCSDN : public ObserverBase
{
private:
string m_name; //观察者名称
public:
ObserverBlogCSDN(string name): m_name(std::move(name)){}
~ObserverBlogCSDN() override = default;
void Update(const BlogBase& blog) override
{
cout<<m_name<<" observer->"<<blog.GetStatus()<<endl; //拉模型
}
};
int main(){
BlogBase *blog = new BlogCSDN("wangdaming");
std::shared_ptr<ObserverBase> pShare1 = std::make_shared<ObserverBlogCSDN>("wangdaming");
blog->Attach(pShare1);
{
std::shared_ptr<ObserverBase> pShare2 = std::make_shared<ObserverBlogCSDN>("others");
blog->Attach(pShare2);
blog->SetStatus("DesignMode");
}
blog->SetStatus("DataStruct");
blog->Remove(pShare1);
delete blog;
return 0;
}