设计模式之责任链模式(二): 实现方式

C++设计模式专栏:http://t.csdnimg.cn/8Ulj3
相关文章系列

设计模式之责任链模式(一)-CSDN博客

目录

1.引言

2.实现方式1

3.实现方式2

4.总结


1.引言

责任链设计模式(Chain of Responsibiliy DesignPattern)简称职责链模式。在GOF的《设计模式:可复用面向对象软件的基础》中,它是这样定义的:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求;将这些接收对象串成一条链,并沿者这条链传递这个请求,直到链上的某个接收对象能够处理它为止(Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it )。

在职责链模式中,多个处理器(也就是定义中所说的"接收对象")依次处理同一个请求。一个请求首先经过A处理器处理,然后,这个请求被传递给B处理器,B处理器处理完后再将其传递给C处理器,以此类推,形成一个链条。因为链条上的每个处理器各自承担各自职责,所以称为职责链模式。

职责链模式有多种实现方式,这里介绍两种常用的。

2.实现方式1

实现方式的代码如下所示。其中,Handler类是所有处理器类的抽象父类,handle()是抽象方法。每个具体的处理器类(HandlerA、HandlerB)的handle()函数的代码结构类似,如果某个处理器能够处理该请求,就不继续往下传递;如果它不能处理,则交由后面的处理器处理(也就是调用successor.handle())。HandlerChain类表示处理器链,从数据结构的角度来看,它就是一个记录了链头、链尾的链表。其中,记录链尾是为了方便添加处理器。

cpp 复制代码
#pragma once
#include <memory>
#include <vector>

class IHandler
{
protected:
	IHandler* m_successor;
public:
	void setSuccessor(IHandler* successor) {
		m_successor = successor;
	}
	virtual void handle() = 0;
};

class HandlerA : public IHandler
{
public:
	//...
	//@override
	void handle() override {
		bool bHandle = false;
		//...
		if (!bHandle && m_successor) {
			m_successor->handle();
		}
		//...
	}
};

class HandlerB : public IHandler
{
public:
	//...
	//@override
	void handle() override {
		bool bHandle = false;
		//...
		if (!bHandle && m_successor) {
			m_successor->handle();
		}
		//...
	}
};

class HandlerChain {
private:
	IHandler* head = nullptr;
	IHandler* tail = nullptr;
public:
	void addHandler(IHandler* handler) {
		handler->setSuccessor(nullptr);
		if (head == nullptr) {
			head = handler;
			tail = handler;
			return;
		}
		tail->setSuccessor(handler);
		tail = handler;
	}
	void handle() {
		if (head != nullptr) {
			head->handle();
		}
	}
};

//使用举例
int main() {
	std::unique_ptr<IHandler> pHandleA(new HandlerA());
	std::unique_ptr<IHandler> pHandleB(new HandlerB());
	HandlerChain chain;

	chain.addHandler(pHandleA.get());
	chain.addHandler(pHandleB.get());

	chain.handle();

    return 1;
}

实际上,上面的代码实现不够优雅,因为处理器类的handle()函数不仅包含自己的业务逻辑。还包含对下一个处理器的调用(对应代码中的successor.handle())。如果一个不熟悉这种代码结构的程序员想要在其中添加新的处理器类,那么很有可能忘记在handle()函数中调用successor.handle(),这就会导致代码出现bug。

设计模式之模板方法模式-CSDN博客

针对这个问题,我们对代码进行重构,利用模版方法模式,将调用successor.handle()的逻辑从处理器中剥离出来,放到抽象父类中。这样,处理器类只需要实现自己的业务逻辑。重构之后的代码如下所示:

cpp 复制代码
class IHandler
{
protected:
	IHandler* m_successor;
public:
	void setSuccessor(IHandler* successor) {
		m_successor = successor;
	}
	void handle() {
		bool bHandled = doHandle();
		if (!bHandled && m_successor) {
			m_successor->handle();
		}
	}
protected:
	virtual bool doHandle() = 0;
};

class HandlerA : public IHandler
{
protected:
	//...
	//@override
	bool doHandle() override {
		bool bHandle = false;
		//...
		return bHandle;
	}
};

class HandlerB : public IHandler
{
protected:
	//...
	//@override
	bool doHandle() override {
		bool bHandle = false;
		//...
		return bHandle;
	}
};

class HandlerChain {
private:
	IHandler* head = nullptr;
	IHandler* tail = nullptr;
public:
	void addHandler(IHandler* handler) {
		handler->setSuccessor(nullptr);
		if (head == nullptr) {
			head = handler;
			tail = handler;
			return;
		}
		tail->setSuccessor(handler);
		tail = handler;
	}
	void handle() {
		if (head != nullptr) {
			head->handle();
		}
	}
};

int  main() {
	std::unique_ptr<IHandler> pHandleA(new HandlerA());
	std::unique_ptr<IHandler> pHandleB(new HandlerB());
	HandlerChain chain;

	chain.addHandler(pHandleA.get());
	chain.addHandler(pHandleB.get());

	chain.handle();

    return 1;
}

3.实现方式2

实现代码如下所示,这种实现方式更加简单,其中HandlerChain 类用数组而非链表来保存所有处理器类,并且在HandlerChain类的handle()函数中,依次调用每个处理器类的 handle()函数。

cpp 复制代码
class IHandler
{
public:
	virtual bool handle() = 0;
};

class HandlerA : public IHandler
{
public:
	//...
	//@override
	bool handle() override {
		bool bHandle = false;
		//...
		return bHandle;
	}
};

class HandlerB : public IHandler
{
public:
	//...
	//@override
	bool handle() override {
		bool bHandle = false;
		//...
		return bHandle;
	}
};

class HandlerChain {
private:
	std::vector<IHandler*> m_vecHandler;
public:
	void addHandler(IHandler* handler) {
		m_vecHandler.push_back(handler);
	}
	void handle() {
		for (auto& it : m_vecHandler) {
			if (it->handle()) {
				break;
			}
		}
	}
};

int main() {
	std::unique_ptr<IHandler> pHandleA(new HandlerA());
	std::unique_ptr<IHandler> pHandleB(new HandlerB());
	HandlerChain chain;

	chain.addHandler(pHandleA.get());
	chain.addHandler(pHandleB.get());

	chain.handle();

    return 1;
}

在GoF合著的《设计模式:可复用面向对象软件的基础》给出的职责链模式的定义中。如果处理器链上的某个处理器能够处理这个请求,就不会继续往下传递请求。实际上,职责链模式还有一种变体,那就是请求会被所有处理器都处理一遍,不存在中途终止的情况。这种变体也有两种实现方式: 用链表存储处理器类和用数组存储处理器类,与上面两种实现方式类似稍加修改即可。这里只给出用链表存储处理器类的实现方式,代码如下所示。对于用数组存储处理器类的实现方式,读者可对照上面的实现自行修改。

cpp 复制代码
class IHandler
{
protected:
	IHandler* m_successor;
public:
	void setSuccessor(IHandler* successor) {
		m_successor = successor;
	}
	void handle() {
		doHandle();
		if (m_successor) {
			m_successor->handle();
		}
	}
protected:
	virtual void doHandle() = 0;
};

class HandlerA : public IHandler
{
protected:
	//...
	//...
	//@override
	void doHandle() override {
		//...
	}
};

class HandlerB : public IHandler
{
protected:
	//...
	//@override
	void doHandle() override {
		//...
	}
};

class HandlerChain {
private:
	IHandler* head = nullptr;
	IHandler* tail = nullptr;
public:
	void addHandler(IHandler* handler) {
		handler->setSuccessor(nullptr);
		if (head == nullptr) {
			head = handler;
			tail = handler;
			return;
		}
		tail->setSuccessor(handler);
		tail = handler;
	}
	void handle() {
		if (head != nullptr) {
			head->handle();
		}
	}
};

int main() {
	std::unique_ptr<IHandler> pHandleA(new HandlerA());
	std::unique_ptr<IHandler> pHandleB(new HandlerB());
	HandlerChain chain;

	chain.addHandler(pHandleA.get());
	chain.addHandler(pHandleB.get());

	chain.handle();

    return 1;
}

4.总结

尽管我们给出了典型的职责链模式的代码实现,但在实际的开发中,我们还是要具体问题具体对待,因为职责链模式的代码实现会根据需求的不同而有所变化。实际上,这一点对于有设计模式都适用。

相关推荐
Stanford_11063 小时前
如何利用Python进行数据分析与可视化的具体操作指南
开发语言·c++·python·微信小程序·微信公众平台·twitter·微信开放平台
千里马-horse4 小时前
Async++ 源码分析8--partitioner.h
开发语言·c++·async++·partitioner
Lucis__5 小时前
再探类&对象——C++入门进阶
开发语言·c++
北京不会遇到西雅图6 小时前
【SLAM】【后端优化】不同优化方法对比
c++·机器人
jndingxin6 小时前
c++多线程(6)------ 条件变量
开发语言·c++
程序员莫小特7 小时前
老题新解|大整数加法
数据结构·c++·算法
洲覆8 小时前
C++ 模板、泛型与 auto 关键字
开发语言·数据结构·c++
千里马-horse9 小时前
Async++ 源码分析7--parallel_reduce.h
开发语言·c++·async++·parallel_reduce
江公望9 小时前
Qt QThread使用方法入门浅解
c++·qt
叫我龙翔9 小时前
【MySQL】从零开始了解数据库开发 --- 数据表的约束
android·c++·mysql·数据库开发