文章目录
前言
设计模式系列文章之行为模式汇总,并且分析他们的原理以及场景。并且分别用c++与go语言进行举例实现。
一、行为模式
行为型模式关注的是系统中对象之间的相互交互,解决系统在运行时对象之间的相互通信和协作,进一步明确对象的职责。
下面分别介绍观察者模式,责任链模式,中介模式,状态模式以及策略模式。
二、观察者模式
场景
消息推送系统:当有新消息到来时,所有订阅该消息的用户都会收到通知。
股票行情系统:当股票价格发生变化时,所有订阅该股票的用户都会收到通知。
GUI编程:当用户界面中的某个控件发生变化时,所有依赖该控件的控件都会自动更新。
当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。
当你使用图形用户界面类时通常会遇到一个问题。 比如, 你创建了自定义按钮类并允许客户端在按钮中注入自定义代码, 这样当用户按下按钮时就会触发这些代码。
观察者模式允许任何实现了订阅者接口的对象订阅发布者对象的事件通知。 你可在按钮中添加订阅机制, 允许客户端通过自定义订阅类注入自定义代码。
当应用中的一些对象必须观察其他对象时, 可使用该模式。 但仅能在有限时间内或特定情况下使用。
原理
**定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。**它还有两个别名,依赖(Dependents),发布-订阅(Publish-Subsrcibe)。可以举个博客订阅的例子,当博主发表新文章的时候,即博主状态发生了改变,那些订阅的读者就会收到通知,然后进行相应的动作,比如去看文章,或者收藏起来。博主与读者之间存在种一对多的依赖关
系。
可以看到博客类中有一个观察者链表(即订阅者),当博客的状态发生变化时,通过Notify成员函数通知所有的观察者,告诉他们博客的状态更新了。而观察者通过Update成员函数获取博客的状态信息
c++实现
首先是观察者的基类 Observer,它定义了一个虚函数 Update。
接下来是博客的基类 Blog,它定义了添加、移除和通知观察者的方法,并且包含观察者链表和一个状态属性。
然后是具体的博客类 BlogCSDN,继承自 Blog,它实现了设置状态和获取状态的方法。
接着是具体的观察者类 ObserverBlog,继承自 Observer,它包含观察者名称和观察的博客对象,并实现了更新方法,在更新时输出观察者名称和博客状态。
使用具体步骤:
观察者通过调用主题的 Attach 方法注册到主题中。
主题维护一个观察者链表,并在状态改变时通过调用观察者的 Update 方法来通知观察者。
观察者接收到通知后,可以通过调用主题的方法来获取状态信息,并执行相应的操作。
//观察者
class Observer
{
public:
Observer() {
}
virtual ~Observer() {
}
virtual void Update() {
}
};
//博客
class Blog
{
public:
Blog() {
}
virtual ~Blog() {
}
void Attach(Observer *observer) {
m_observers.push_back(observer); } //添加观察者
void Remove(Observer *observer) {
m_observers.remove(observer); } //移除观察者
void Notify() //通知观察者
{
list<Observer*>::iterator iter = m_observers.begin();
for(; iter != m_observers.end(); iter++)
(*iter)->Update();
}
virtual void SetStatus(string s) {
m_status = s; } //设置状态
virtual string GetStatus() {
return m_status; } //获得状态
private:
list<Observer* > m_observers; //观察者链表
protected:
string m_status; //状态
};
//具体博客类
class BlogCSDN : public Blog
{
private:
string m_name; //博主名称
public:
BlogCSDN(string name): m_name(name) {
}
~BlogCSDN() {
}
void SetStatus(string s) {
m_status = "CSDN通知 : " + m_name + s; } //具体设置状态信息
string GetStatus() {
return m_status; }
};
//具体观察者
class ObserverBlog : public Observer
{
private:
string m_name; //观察者名称
Blog *m_blog; //观察的博客,当然以链表形式更好,就可以观察多个博客
public:
ObserverBlog(string name,Blog *blog): m_name(name), m_blog(blog) {
}
~ObserverBlog() {
}
void Update() //获得更新状态
{
string status = m_blog->GetStatus();
cout<<m_name<<"-------"<<status<<endl;
}
};
//测试案例
int main()
{
Blog *blog = new BlogCSDN("1985");
Observer *observer1 = new ObserverBlog("ad", blog);
blog->Attach(observer1);
blog->SetStatus("发表——观察者模式");
blog->Notify();
delete blog; delete observer1;
return 0;
}
go实现
在 Go 语言中,我们使用接口来实现多态性。首先定义了 Observer 接口,它包含了 Update() 方法。
然后定义了 Subject 接口,它包含了添加观察者、移除观察者、通知观察者等方法,以及获取和设置状态的方法。
接着是 BlogCSDN 结构体,它实现了 Subject 接口,用于具体的博客主题。这里使用了 Go 语言中的双向链表来存储观察者。
package main
import (
"container/list"
"fmt"
)
// 观察者接口
type Observer interface {
Update()
}
// 主题接口
type Subject interface {
Attach(observer Observer)
Remove(observer Observer)
Notify()
SetStatus(status string)
GetStatus() string
}
// 具体主题类
type BlogCSDN struct {
name string
status string
observers *list.List
}
func NewBlogCSDN(name string) *BlogCSDN {
return &BlogCSDN{
name: name,
observers: list.New(),
}
}
func (b *BlogCSDN) Attach(observer Observer) {
b.observers.PushBack(observer)
}
func (b *BlogCSDN) Remove(observer Observer) {
for item := b.observers.Front(); item != nil; item = item.Next() {
if item.Value.(Observer) == observer {
b.observers.Remove(item)
break
}
}
}
func (b *BlogCSDN) Notify() {
for item := b.observers.Front(); item != nil; item = item.Next() {
item.Value.(Observer).Update()
}
}
func (b *BlogCSDN) SetStatus(status string) {
b.status = "CSDN通知: " + b.name + status
}
func (b *BlogCSDN) GetStatus() string {
return b.status
}
// 具体观察者类
type ObserverBlog struct {
name string
blog Subject
}
func NewObserverBlog(name string, blog Subject) *ObserverBlog {
return &ObserverBlog{
name: name,
blog: blog,
}
}
func (o *ObserverBlog) Update() {
status := o.blog.GetStatus()
fmt.Printf("%s-------%s\n", o.name, status)
}
func main() {
blog := NewBlogCSDN("wuzhekai1985")
observer1 := NewObserverBlog("tutupig", blog)
blog.Attach(observer1)
blog.SetStatus("发表设计模式C++实现(15)——观察者模式")
blog.Notify()
}
三、责任链模式
场景
当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。
该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。
当必须按顺序执行多个处理者时, 可以使用该模式。
无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。
如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。
如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序
原理
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。其思想很简单,考虑员工要求加薪。公司的管理者一共有三级,总经理、总监、经理,如果一个员工要求加薪,应该向主管的经理申请,如果加薪的数量在经理的职权内,那么经理可以直接批准,否则将申请上交给总监。总监的处理方式也一样,总经理可以处理所有请求。这就是典型的职责链模式,请求的处理形成了一条链,直到有一个对象处理请求。给出这个例子的UML图。