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

发布于:2024-04-26 ⋅ 阅读:(26) ⋅ 点赞:(0)

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类表示处理器链,从数据结构的角度来看,它就是一个记录了链头、链尾的链表。其中,记录链尾是为了方便添加处理器。

#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()的逻辑从处理器中剥离出来,放到抽象父类中。这样,处理器类只需要实现自己的业务逻辑。重构之后的代码如下所示:

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()函数。

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

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.总结        

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


网站公告

今日签到

点亮在社区的每一天
去签到