面向对象设计模式--责任链模式(C++可执行代码)

责任链模式

(Chain of Responsibility)

        责任链 是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。

1. 问题

        假如你正在开发一个在线订购系统。你希望对系统访问进行限制,只允许认证用户创建订单。此外,拥有管理权限的用户也拥有所有订单的完全访问权限。

        简单规划后,你会意识到这些检查必须依次进行。只要接收到包含用户凭据的请求,应用程序就可尝试对进入系统的用户进行认证。 但如果由于用户凭据不正确而导致认证失败,那就没有必要进行后续检查了。

请求必须经过一系列检查后才能由订购系统来处理

        在接下来的几个月里,你实现了后续的几个检查步骤。

        • 一位同事认为直接将原始数据传递给订购系统存在安全隐患。因此你新增了额外的验证步骤来清理请求中的数据。

        • 过了一段时间,有人注意到系统无法抵御暴力密码破解方式的攻击。为了防范这种情况,你立刻添加了一个检查步骤来过滤来自同一 IP 地址的重复错误请求。

        • 又有人提议你可以对包含同样数据的重复请求返回缓存中的结果,从而提高系统响应速度。因此,你新增了一个检查步骤,确保只有没有满足条件的缓存结果时请求才能通过并被发送给系统。

        检查代码本来就已经混乱不堪,而每次新增功能都会使其更加臃肿。修改某个检查步骤有时会影响其他的检查步骤。最糟糕的是,当你希望复用这些检查步骤来保护其他系统组件 时,你只能复制部分代码,因为这些组件只需部分而非全部的检查步骤。

        系统会变得让人非常费解,而且其维护成本也会激增。你在艰难地和这些代码共处一段时间后,有一天终于决定对整个系统进行重构。

代码变得越来越多,也越来越混乱

2. 解决方案

        与许多其他行为设计模式一样,责任链会将特定行为转换为被称作处理者的独立对象。在上述示例中,每个检查步骤都可被抽取为仅有单个方法的类,并执行检查操作。请求及其数据则会被作为参数传递给该方法。

        模式建议你将这些处理者连成一条链。链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。除了处理请求外,处理者还负责沿着链传递请求。请求会在链上移动,直至所有处理者都有机会对其进行处理。

        最重要的是:处理者可以决定不再沿着链传递请求,这可高效地取消所有后续处理步骤。

        在我们的订购系统示例中,处理者会在进行请求处理工作后决定是否继续沿着链传递请求。如果请求中包含正确的数据,所有处理者都将执行自己的主要行为,无论该行为是身份验证还是数据缓存。

处理者依次排列,组成一条链

        不过还有一种稍微不同的方式(也是更经典一种),那就是处理者接收到请求后自行决定是否能够对其进行处理。如果自己能够处理,处理者就不再继续传递请求。因此在这种情况下,每个请求要么最多有一个处理者对其进行处理,要么没有任何处理者对其进行处理。在处理图形用户界面元素栈中的事件时,这种方式非常常见。

3. 结构

责任链模式结构

        其中:

        *Handler定义一个处理请求的接口; (可选) 实现后继链。

        *Concrete Handler处理它所负责的请求; 可访问它的后继者; 如果可处理该请求, 就处理它,否则将该请求转发给后继者。

        *Client向链上的具体处理者(Concrete Handler) 对象提交请求。

4. 实现方式

1. 声明处理者接口并描述请求处理方法的签名。

        确定客户端如何将请求数据传递给方法。最灵活的方式是将请求转换为对象,然后将其以参数的形式传递给处理函数。

2. 为了在具体处理者中消除重复的样本代码,你可以根据处理者接口创建抽象处理者基类。

        该类需要有一个成员变量来存储指向链上下个处理者的引用。你可以将其设置为不可变类。但如果你打算在运行时对链进行改变,则需要定义一个设定方法来修改引用成员变量的值。

        为了使用方便,你还可以实现处理方法的默认行为。如果还有剩余对象,该方法会将请求传递给下个对象。具体处理者还能够通过调用父对象的方法来使用这一行为。

3. 依次创建具体处理者子类并实现其处理方法。

        每个处理者在接收到请求后都必须做出两个决定:

        ◦ 是否自行处理这个请求。

        ◦ 是否将该请求沿着链进行传递。

4. 客户端可以自行组装链,或者从其他对象处获得预先组装好的链。

        在后一种情况下,你必须实现工厂类以根据配置或环境设置来创建链。

5. 客户端可以触发链中的任意处理者,而不仅仅是第一个。

        请求将通过链进行传递,直至某个处理者拒绝继续传递,或者请求到达链尾。

6. 由于链的动态性,客户端需要准备好处理以下情况:

        ◦ 链中可能只有单个链接。

        ◦ 部分请求可能无法到达链尾。

        ◦ 其他请求可能直到链尾都未被处理。

5. 代码示例

chain_of_responsibility.h

#ifndef DESIGN_PATTERNS_CHAIN_OF_RESPONSIBILITY_H
#define DESIGN_PATTERNS_CHAIN_OF_RESPONSIBILITY_H
#include <iostream>
#include <string>
using namespace std;
//------------------------------//
class Request		//"需求"类
{
public:
	Request() {}
	Request(string, int);
	string GetType();//获取类型
	int GetNumber();//获取数字

private:
	string type_;
	int number_;
};
//------------------------------//
class Manager //“管理者”类
{
public:
	Manager() {}
	Manager(string);
	void SetSuperior(Manager *);//设置上级
	virtual void RequestApplications(Request *) = 0;//"需求"应用程序

protected:
	Manager *superior_;
	string name_;
};

class CommonManager : public Manager //"经理"
{
public:
	CommonManager(string);
	void RequestApplications(Request *);
};

class Majordomo : public Manager //"总监"
{
public:
	Majordomo(string);
	void RequestApplications(Request *);
};

class GeneralManager : public Manager //"总经理"
{
public:
	GeneralManager(string);
	void RequestApplications(Request *);
};
//------------------------------//
#endif //DESIGN_PATTERNS_CHAIN_OF_RESPONSIBILITY_H

chain_of_responsibility.c

#include "chain_of_responsibility.h"
//------------------------------//
Request::Request(string type, int number) : type_(type), number_(number) {}

int Request::GetNumber() 
{
	return number_;
}

string Request::GetType() 
{
	return type_;
}

//------------------------------//
Manager::Manager(string name) : name_(name) {}

void Manager::SetSuperior(Manager *superior) 
{
	superior_ = superior;
}

//------------------------------//
CommonManager::CommonManager(string name) : Manager(name) {}

void CommonManager::RequestApplications(Request *request) 
{
	if (request->GetType() == "请假单" && request->GetNumber() <= 2)
	{
		cout << name_ << " : 批准" << endl;
	}
	else 
	{
		superior_->RequestApplications(request);
	}
}

//------------------------------//
Majordomo::Majordomo(string name) : Manager(name) {}

void Majordomo::RequestApplications(Request *request) 
{
	if (request->GetType() == "请假单" && request->GetNumber() <= 5)
	{
		cout << name_ << " : 批准" << endl;
	}
	else 
	{
		superior_->RequestApplications(request);
	}
}
//------------------------------//
GeneralManager::GeneralManager(string name) : Manager(name) {}

void GeneralManager::RequestApplications(Request *request) 
{
	if (request->GetType() == "请假单")
	{
		cout << name_ << " : 批准" << endl;
	}
	else if (request->GetType() == "加薪单" && request->GetNumber() <= 500)
	{
		cout << name_ << " : 批准" << endl;
	}
	else 
	{
		cout << name_ << " :不批准" << endl;
	}
}
//------------------------------//

Main.c

//------------------------------//
#include <iostream>
#include "chain_of_responsibility.h"
using namespace std;
//------------------------------//
// Created by Cls on 2024/04/01.
//------------------------------//
int main(int argc, char *argv[])
{
	Request *request1_, *request2_;
	CommonManager *common_manager_;
	Majordomo *majordomo_;
	GeneralManager *general_manager_;
	//-----------------//
	common_manager_ = new CommonManager("经理");
	majordomo_ = new Majordomo("总监");
	general_manager_ = new GeneralManager("总经理");

	//-----------------//
	common_manager_->SetSuperior(majordomo_);
	majordomo_->SetSuperior(general_manager_);
	cout << "------------------" << endl;

	//-----------------//
	request1_ = new Request("请假单", 4);
	common_manager_->RequestApplications(request1_);
	cout << "------------------" << endl;

	//-----------------//
	request2_ = new Request("加薪单", 1000);
	common_manager_->RequestApplications(request2_);
	cout << "------------------" << endl;

	//-----------------//
	delete request1_;
	delete request2_;
	delete common_manager_;
	delete majordomo_;
	delete general_manager_;
	//-----------------//
	return 0;
}
//------------------------------//

打印输出

6. 应用场景

当程序需要使用不同方式处理不同种类请求,而且请求类型和顺序预先未知时,可以使用责任链模式。

        该模式能将多个处理者连接成一条链。接收到请求后,它会“询问”每个处理者是否能够对其进行处理。这样所有处理者都有机会来处理请求。

当必须按顺序执行多个处理者时,可以使用该模式。

        无论你以何种顺序将处理者连接成一条链,所有请求都会严格按照顺序通过链上的处理者。

如果所需处理者及其顺序必须在运行时进行改变,可以使用责任链模式。

        如果在处理者类中有对引用成员变量的设定方法,你将能动态地插入和移除处理者,或者改变其顺序。

7. 优缺点

        √ 你可以控制请求处理的顺序。

        √ 单一职责原则。你可对发起操作和执行操作的类进行解耦。

        √ 开闭原则。你可以在不更改现有代码的情况下在程序中新增处理者。

        × 部分请求可能未被处理。

8. 与其他模式的关系

        责任链、命令、中介者和观察者用于处理请求发送者和接收者之间的不同连接方式:

        ---- 责任链按照顺序将请求动态传递给一系列的潜在接收者,直至其中一名接收者对请求进行处理。

        ---- 命令在发送者和请求者之间建立单向连接。

        ---- 中介者清除了发送者和请求者之间的直接连接,强制它们通过一个中介对象进行间接沟通。

        ---- 观察者允许接收者动态地订阅或取消接收请求。

        责任链和装饰模式的类结构非常相似。两者都依赖递归组合将需要执行的操作传递给一系列对象。但是,两者有几点重要的不同之处。

        ---- 责任链的管理者可以相互独立地执行一切操作,还可以随时停止传递请求。另一方面,各种装饰可以在遵循基本接口的情况下扩展对象的行为。此外,装饰无法中断请求的传递。

  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值