栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > Java

【Chain of Resposibility】C++设计模式——职责链

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Chain of Resposibility】C++设计模式——职责链

职责链
  • 一、设计流程探讨
  • 二、模式介绍
  • 三、代码实现

    C++设计模式大全,23种设计模式合集详解—(点我跳转)

一、设计流程探讨

  假如你正在开发一个在线订购系统。你希望对系统访问进行限制,只允许认证用户创建订单。此外,拥有管理权限的用户也拥有所有订单的完全访问权限。
  简单规划后,你会意识到这些检查必须依次进行。只要接收到包含用户凭据的请求,应用程序就可尝试对进入系统的用户进行认证。但如果由于用户凭据不正确而导致认证失败,那就没有必要进行后续检查了。

在接下来的几个月里,你实现了后续的几个检查步骤。
 ● 一位同事认为直接将原始数据传递给订购系统存在安全隐患。因此你新增了额外的验证步骤来处理请求中的数据。
 ● 过了一段时间,有人注意到系统无法抵御暴力密码破解方式的攻击。为了防范这种情况,你立刻添加了一个检查步骤来过滤来自同一IP地址的重复错误请求。
 ● 又有人提议你可以对包含同样数据的重复请求返回缓存中的结果,从而提高系统响应速度。因此,你新增了一个检查步骤,确保只有没有满足条件的缓存结果时请求才能通过并被发送给系统。

  检查代码本来就已经混乱不堪,而每次新增功能都会使其更加臃肿。修改某个检查步骤有时会影响其他的检查步骤。最糟糕的是,当你希望复用这些检查步骤来保护其他系统组件时,你只能复制部分代码,因为这些组件只需部分而非全部的检查步骤。
  系统会变得让人非常费解,而且其维护成本也会激增。你在艰难地和这些代码共处一段时间后,有一天终于决定对整个系统进行重构。
解决方案:
  与许多其他行为设计模式一样,责任链会将特定行为转换为被称作处理者的独立对象。在上述示例中,每个检查步骤都可被抽取为仅有单个方法的类,并执行检查操作。请求及其数据则会被作为参数传递给该方法。
  模式建议你将这些处理者连成一条链。链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。除了处理请求外,处理者还负责沿着链传递请求。请求会在链上移动,直至所有处理者都有机会对其进行处理。
  最重要的是:处理者可以决定不再沿着链传递请求,这可高效地取消所有后续处理步骤。
  在我们的订购系统示例中,处理者会在进行请求处理工作后决定是否继续沿着链传递请求。如果请求中包含正确的数据,所有处理者都将执行自己的主要行为,无论该行为是身份验证还是数据缓存。

  不过还有一种稍微不同的方式(也是更经典一种),那就是处理者接收到请求后自行决定是否能够对其进行处理。如果自己能够处理,处理者就不再继续传递请求。因此在这种情况下,每个请求要么最多有一个处理者对其进行处理,要么没有任何处理者对其进行处理。在处理图形用户界面元素栈中的事件时,这种方式非常常见。
  例如,当用户点击按钮时,按钮产生的事件将沿着 GUI 元素链进行传递,最开始是按钮的容器(如窗体或面板),直至应用程序主窗口。链上第一个能处理该事件的元素会对其进行处理。此外,该例还有另一个值得我们关注的地方:它表明我们总能从对象树中抽取出链来。

  所有处理者类均实现同一接口是关键所在。每个具体处理者仅关心下一个包含 execute执行方法的处理者。这样一来,你就可以在运行时使用不同的处理者来创建链,而无需将相关代码与处理者的具体类进行耦合。

真实世界类比:

  最近,你刚为自己的电脑购买并安装了一个新的硬件设备。身为一名极客,你显然在电脑上安装了多个操作系统,所以你会试着启动所有操作系统来确认其是否支持新的硬件设备。Windows 检测到了该硬件设备并对其进行了自动启用。但是你喜爱的 Linux 系统并不支持新硬件设备。抱着最后一点希望,你决定拨打包装盒上的技术支持电话。
  首先你会听到自动回复器的机器合成语音,它提供了针对各种问题的九个常用解决方案,但其中没有一个与你遇到的问题相关。过了一会儿,机器人将你转接到人工接听人员处。
  这位接听人员同样无法提供任何具体的解决方案。他不断地引用手册中冗长的内容,并不会仔细聆听你的回应。在第 10 次听到 “你是否关闭计算机后重新启动呢?” 这句话后,你要求与一位真正的工程师通话。
  最后,接听人员将你的电话转接给了工程师,他或许正缩在某幢办公大楼的阴暗地下室中,坐在他所深爱的服务器机房里,焦躁不安地期待着同一名真人交流。工程师告诉了你新硬件设备驱动程序的下载网址,以及如何在 Linux 系统上进行安装。问题终于解决了!你挂断了电话,满心欢喜。

二、模式介绍

(1)模式动机
  在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显式指定,将必不可少地带来请求发送者与接受者的紧耦合。
  如何使请求的发送者不需要指定具体的接受者,让请求的接受者自己在运行时决定来处理请求,从而使两者解耦
(2)模式定义
  使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
(3)要点总结
a). Chain of Responsibility 模式的应用场合在于 “一个请求可能有多个接受者,但是最后真正的接受者只有一个”,这时候请求发送者与接受者的耦合有可能出现 “变化脆弱” 的症状,职责链的目的就是将二者解耦,从而更好地应对变化。
b). 应用了Chain of Responsibility 模式后,对象的职责分派将更具灵活性,我们可以在运行时动态添加 / 修改请求的处理职责。
c). 如果请求传递到职责链的末尾仍得不到处理,应该有一个合理的缺省机制。这也是每一个接受对象的责任,而不是发出请求的对象的责任。

三、代码实现

  下面将用伪代码实现职责链模式,但该模式在平常使用不多,下图是方便大家理解的类图结构。

enum class RequestType{
	REQ_HANDLER1,
	REQ_HANDLER2,
	REQ_HANDLER3
};
class Request{
	string description;
	RequestType reqType;
public:
	Request(const string &desc, RequestType type) : description(desc),reqType(type) {}
	RequestType getReqType() const { return reqType; }
	const string& getDescription() const { return description; }
};
class ChainHandler{
	ChainHandler *nextChain;		//指针指向自身,多态指针,形成了个多态链表
	void sendRequestToNextHandler(const Request &req){
		if (nextChain != nullptr)
			nextChain->handle(req);
	}
protected:
	virtual bool canHandleRequest(const Request &req) = 0;		//这里是虚函数,相当于运行时来判断
	virtual void processRequest(const Request &req) = 0;
public:
	ChainHandler() { nextChain = nullptr; }
	void setNextChain(ChainHandler *next) { nextChain = next; }
	void handle(const Request &req){
		if (canHandleRequest(req))
			processRequest(req);
		else
			sendRequestToNextHandler(req);
	}
};
class Handler1 : public ChainHandler{
protected:
	bool canHandleRequest(const Request &req) override{
			//这为了简单就采用枚举类,实际上是会复杂点(一般根据业务缺点)
			return req.getReqType() == RequestType::REQ_HANDLER1;
	}
	void processRequest(const Request &req) override{
		cout << "Handler1 is handle request: " << req.getDescription() << endl;
	}
};
class Handler2 : public ChainHandler{
protected:
	bool canHandleRequest(const Request &req) override{
			//这为了简单就采用枚举类,实际上是会复杂点(一般根据业务缺点)
			return req.getReqType() == RequestType::REQ_HANDLER2;
	}
	void processRequest(const Request &req) override{
		cout << "Handler2 is handle request: " << req.getDescription() << endl;
	}
};
class Handler3 : public ChainHandler{
	//... 与 Handler1 和 Handler2 同理
};
int main(){
	Handler1 h1;
	Handler2 h2;
	Handler3 h3;
	h1.setNextChain(&h2);
	h2.setNextChain(&h3);

	Request req("process task ...", RequestType::REQ_HANDLER3);
	h1.hand(req);
	return 0;
}
转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1040830.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号