定义:定义对象间一对多的依赖关系,当其中一个对象发生变化时,所有依赖于它的对象都会得到更新。
类图:
在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化。
观察者模式的结构
在最基础的观察者模式中,包括以下四个角色:
- 被观察者:从类图中可以看到,类中有一个用来存放观察者对象的Vector容器(之所以使用Vector而不使用List,是因为多线程操作时,Vector在是安全的,而List则是不安全的),这个Vector容器是被观察者类的核心,另外还有三个方法:attach方法是向这个容器中添加观察者对象;detach方法是从容器中移除观察者对象;notify方法是依次调用观察者对象的对应方法。这个角色可以是接口,也可以是抽象类或者具体的类,因为很多情况下会与其他的模式混用,所以使用抽象类的情况比较多。
- 观察者:观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生变化时,这个方法就会被触发调用。
- 具体的被观察者:使用这个角色是为了便于扩展,可以在此角色中定义具体的业务逻辑。
- 具体的观察者:观察者接口的具体实现,在这个角色中,将定义被观察者对象状态发生变化时所要处理的逻辑。
适用性:
1.当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
2.当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
3.当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。
优缺点:
观察者模式的效果有以下几个优点:
1.观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体现察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
2.观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。
观察者模式有下面的一些缺点:
1.如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2.如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察考模式时要特别注意这一点。
3.如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
4.虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
举例:
//The abstract Observer class to define the basic operation
class Observer
{
public:
Observer() {}
virtual ~Observer() {}
virtual void Update() {}
};
//The abstract Observered class to define the given operation
class Blog
{
public:
Blog() {}
virtual ~Blog() {}
void Attach(Observer *observer) { m_observers.push_back(observer); } //add a observer
void Remove(Observer *observer) { m_observers.remove(observer); } //remove a observer
void Notify() //update the observer
{
list<Observer*>::iterator iter = m_observers.begin();
for(; iter != m_observers.end(); iter++)
(*iter)->Update();
}
virtual void SetStatus(string s) { m_status = s; } //set the status
virtual string GetStatus() { return m_status; } //get the status
private:
list<Observer*> m_observers; //new a list to store the observer, the best way is to use a vector
protected:
string m_status; //status
};
class BlogCSDN : public Blog
{
private:
string m_name; //name
public:
BlogCSDN(string name): m_name(name) {}
~BlogCSDN() {}
void SetStatus(string s)
{
m_status = "CSDN notify : " + m_name + s;
} //set the status
string GetStatus()
{
return m_status;
}
};
//The specific observer
class ObserverBlog : public Observer
{
private:
string m_name; //name
Blog *m_blog; //the specific observer object
public:
ObserverBlog(string name,Blog *blog): m_name(name), m_blog(blog) {}
~ObserverBlog() {}
void Update() //update the status
{
string status = m_blog->GetStatus();
cout<<m_name<<"-------"<<status<<endl;
}
};
int main()
{
cout<<"\n--------------start of the main()---------------"<<endl;
Blog *blog = new BlogCSDN("helloworld");
Observer *observer1 = new ObserverBlog("observer number 1", blog);
blog->Attach(observer1);
blog->SetStatus(" read one article");
blog->Notify();
delete blog;
blog = NULL;
delete observer1;
observer1 = NULL;
cout<<"\n--------------end of the main()---------------"<<endl;
return 0;
}