观察者模式也叫做发布-订阅(Publish-Subscribe)。Redis中有一个发布订阅功能,类似此模式。
Redis pub/sub
Redis作为一个pub/sub server,在订阅者和发布者之间起到了消息路由的功能。订阅者可以通过subscrible和psubscribe命令向redis server订阅自己感兴趣的消息类型。当发布者通过publish命令向redis server发送特定类型的消息时,该消息类型(通道)的所有client都会被推送此消息。
做以下实验:
1.启动redis-server
2.启动一个redis-cli A订阅一个使用通配符的通道(*表示任意字符串):
127.0.0.1:6379> PSUBSCRIBE news.*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "news.*"
3) (integer) 1
3.启动一个redis-cli B订阅一个特定的通道:
127.0.0.1:6379> SUBSCRIBE news.sports
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "news.sports"
3) (integer) 1
4.启动一个redis-cli C发布消息:
127.0.0.1:6379> publish news.sports "basketball win"
(integer) 2
可以看到client A打印:
1) "pmessage"
2) "news.*"
3) "news.sports"
4) "basketball win"
client B打印:
1) "message"
2) "news.sports"
3) "basketball win"
发布消息的client C返回的(integer)2表示有两个redis-cli连接收到了此消息。
这就是Redis的订阅发布功能,常见的应用场景有:多人聊天,邮件服务器,记录站点操作日志,站内信等。
观察者模式
观察者模式定义了一种这样的场景,当一个对象的状态发生改变时,所有和它有关系的对象都应该得到通知并自动更新此对象。
现在实现一个简单的博客订阅的例子。当博主发布新文章时,那些订阅的读者就会收到通知,然后产生相应的动作(查看,收藏,转载)。
UML图
用一个奇葩的在线软件画的,限制免费用户使用20个parameter。所以省去了构造和析构函数。线也无法连接,于是我开启了PS。
实现
class Observer
{
public:
Observer() {};
virtual ~Observer() {};
virtual void Update() {};
};
class Blog
{
public:
Blog() {}
virtual ~Blog() {}
void Notify()
{
for(auto ob: observers)
ob->Update();
}
void Attach(Observer* observer)
{
observers.push_back(observer);
}
void Detach(Observer* observer)
{
observers.remove(observer);
}
virtual string GetStatus()
{
return m_status;
}
virtual void SetStatus(string status)
{
m_status = status;
}
private:
list<Observer*> observers;
protected:
string m_status; //让子类可以访问
};
class GithubBlog: public Blog
{
public:
GithubBlog(string name): blogname(name) {}
~GithubBlog() {}
string GetStatus() { return m_status; }
void SetStatus(string status)
{
m_status = "GithubBlog-" + blogname + "通知" + status;
this->Notify();
}
private:
string blogname;
};
class SomeObserver: public Observer
{
public:
SomeObserver(string name, Blog* blog):
_name(name),
_blog(blog) {}
~SomeObserver() {}
void Update()
{
string status = _blog->GetStatus();
cout << "用户:" << _name << " " << status << endl;
}
private:
string _name;
Blog* _blog;
};
int main()
{
Blog *tecblog = new GithubBlog("青碧");
Observer *user1 = new SomeObserver("兔之", tecblog);
tecblog->Attach(user1);
Observer *user2 = new SomeObserver("小司", tecblog);
tecblog->Attach(user2);
tecblog->SetStatus("C++之观察者模式");
//tecblog->Notify();
delete tecblog;
delete user1;
delete user2;
return 0;
}
核心的逻辑是在Blog中保存指向所有Observer的指针,而在具体的观察者类中保存指向需要观察Blog的指针(观察多个时为链表)。
Reference
[1].http://www.wzxue.com
[2].http://blog.csdn.net/wuzhekai1985/article/details/6674984