情景描述
中国国代对妇女制定了"三从四德"的道德规范 , “三从"是指"未嫁从父 , 既嫁从夫 , 夫死从子” . 举例来说 , 如果一位女性要出去逛街 , 在她出嫁之前必须征得父亲的同意 , 出家之后必须获得丈夫的许可 , 那丈夫死了怎么办?那就得问问儿子是否允许自己出去逛街 . 我们来分析一下需求 , 女性提出一个请示 , 必然要获得一个答复 , 甭管是同意还是不同意 , 总之是要一个答复 , 而这个答复是唯一的 , 不能说父亲做出一个决断 , 而丈夫也做出一个决断 , 也即是请示传递传出去 , 必然有一个唯一的处理人给出一个答复 .
我们可以抽象成这样一个结构 , 女性的请求先发送到父亲类 , 父亲类一看是自己要处理的 , 就做出回应处理 , 如果女儿已经出嫁了 , 那就要把这个请求转发到女婿来处理 , 那女婿一旦去天国报到了 , 那就由儿子来处理这个请求了 . 类似于如图所示的顺序处理图 :
顺序处理的类图 :
代码实现 :
#include<iostream>
#include<string>
//#include<vld.h>
#define FATHER_LEVEL_REQUEST 1
#define HUSBAND_LEVEL_REQUEST 2
#define SON_LEVEL_REQUEST 3
using namespace std;
//责任链模式
#if 0
//女性接口
class IWomen
{
public:
//获得个人状况
virtual int getType() = 0;
//获得个人请示 , 你要干什么? 出去逛街?约会?看电影?
virtual string getRequest() = 0;
};
//古代妇女
class Women : public IWomen
{
/*
*通过一个int类型的参数来描述妇女的个人状况
*1----未出嫁
*2----出嫁
*3----夫死
*/
public:
//构造函数传递过来的请求
Women(int _type = 0,string _request = " ")
{
type = _type;
switch (type)
{
case 1:
request = "女儿的请求是 : "+ _request;
break;
case 2:
request = "妻子的请求是 : "+ _request;
break;
case 3:
request = "母亲的请求是 : "+ _request;
break;
default:
break;
}
}
//获得自己的状况
int getType()
{
return type;
}
//获得妇女的请求
string getRequest()
{
return request;
}
private:
int type ;
//妇女的请示
string request;
};
//有处理权的人员接口
class IHandler
{
public:
//每个类都要说明自己能处理哪些请求
IHandler(int n)
: level(n) , nextHandler(nullptr)
{}
//一个女性(女儿 , 妻子或者母亲) 要求逛街 , 你要处理这个请求
void HandleMessage(IWomen* women)
{
if(women->getType() == level)
response(women);
else
{
//有后续环节 , 才能把请求往后送
if(nextHandler != nullptr)
nextHandler->HandleMessage(women);
else
//已经没有后续处理人 , 不用处理
cout<<"----没地方请示了 , 按不同意处理-----"<<endl;
}
}
/*
*如果不属于你处理的请求 , 你应该让她找下一个环节的人 , 如女儿出嫁了
*还想父亲请示是否可以逛街 , 那父亲就应该告诉女儿 , 应该找丈夫请示
*/
void setNext(IHandler* _handler)
{
nextHandler = _handler;
}
protected:
//有请示那当然要回应
virtual void response(IWomen* women) = 0;
private:
//能处理的级别
int level;
//责任传递 , 下一个责任人是谁
IHandler* nextHandler;
};
//父亲类
class Father : public IHandler
{
public:
Father()
:IHandler(FATHER_LEVEL_REQUEST)
{}
//父亲只处理女儿的请求
void response(IWomen* women)
{
cout<<"-----------------女儿向父亲请示------------------"<<endl;
cout<<women->getRequest()<<endl;
cout<<"父亲的答复是 : 同意"<<endl;
}
};
//丈夫类
class Husband : public IHandler
{
public:
Husband()
:IHandler(HUSBAND_LEVEL_REQUEST)
{}
void response(IWomen* women)
{
cout<<"-----------------妻子向丈夫请示------------------"<<endl;
cout<<women->getRequest()<<endl;
cout<<"丈夫的答复是 : 同意"<<endl;
}
};
//儿子类
class Son : public IHandler
{
public:
Son()
:IHandler(SON_LEVEL_REQUEST)
{}
void response(IWomen* women)
{
cout<<"-----------------母亲向女儿请示------------------"<<endl;
cout<<women->getRequest()<<endl;
cout<<"儿子的答复是 : 同意"<<endl;
}
};
int main()
{
Women* women1 = new Women(1,"我要出去逛街");
Women* women2 = new Women(2,"我要出去逛街");
Women* women3 = new Women(3,"我要出去逛街");
IHandler* father = new Father();
IHandler* husband = new Husband();
IHandler* son = new Son();
father->setNext(husband);
husband->setNext(son);
father->HandleMessage(women1);
father->HandleMessage(women2);
father->HandleMessage(women3);
delete women1; delete women2; delete women3;
delete father;
delete husband;
delete son;
return 0;
}
#endif
运行结果 :
责任链模式的定义
定义 : 使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系 . 将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止 .
责任链模式的重点在" 链 "上 , 由一条链去处理相似的请求在链中决定谁来处理这个请求 , 并返回相应的结果 .
责任链模式通用类图 :
责任连模式的结构
抽象的处理者(Handler)实现三个职责:
- 一是定义一个请求的处理方法handleMessage, 唯一对外开放的方法 ;
- 二是定义一个链的编排方法setNext,设置下一个处理者;
- 三是定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别getHandlerLevel和具体的处理任务echo .
责任链模式的应用
责任链模式的优点
责任链模式非常显著的优点是将请求和处理分开 . 请求者可以不用知道是谁处理的,处理者可以不用知道请求的全貌 .
责任链模式的缺点
责任链有两个非常显著的缺点:
- 一是性能问题,每个请求都是从链头遍历到链尾,特别是在链比较长的时候,性能是一个非常大的问题 .
- 二是调试不很方便,特别是链条比较长,环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑可能比较复杂 .
责任链模式的注意事项
链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个最大节点数量,在setNext方法中判断是否已经是超过其阈值,超过则不允许该链建立,避免无意识地破坏系统性能 .
参考书籍 :
<<设计模式之禅 第二版>>
<<设计模式>>