23种设计模式之责任链模式(Chain of Responsibility Pattern)
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了
优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点: 1、不能保证请求一定被接收。 2、在找到正确的处理对象之前,所有的条件判定都要执行一遍,当责任链过长时,可能会引起性能的问题。 3、可能不容易观察运行时的特征,有碍于除错。
应用实例: 1、JS 中的事件冒泡。2、在现实生活中,有很多请求并不是一个人说了就算的,例如面试时的工资,低于1万的薪水可能技术经理就可以决定了,但是1万~1万5的薪水可能技术经理就没这个权利批准,可能就需要请求技术总监的批准,所以在面试的完后,经常会有面试官说,你这个薪水我这边觉得你这技术可以拿这个薪水的,但是还需要技术总监的批准等的话。
主要涉及两个角色:
- 抽象处理者角色(Handler):定义出一个处理请求的接口。这个接口通常由接口或抽象类来实现。
- 具体处理者角色(ConcreteHandler):具体处理者接受到请求后,可以选择将该请求处理掉,或者将请求传给下一个处理者。因此,每个具体处理者需要保存下一个处理者的引用,以便把请求传递下去
实现代码:
public abstract class AbstractAuditor
{
public string Name { get; set; }
public abstract void Audit(ApplyContext context); private AbstractAuditor _NextAuditor = null;
public void SetNext(AbstractAuditor auditor)
{
this._NextAuditor = auditor;
}
protected void AuditNext(ApplyContext context)
{
if (this._NextAuditor != null)
{
this._NextAuditor.Audit(context);
}
else
{
context.AuditResult = false;
context.AuditRemark = "不允许请假!";
}
}
}
/// <summary>
/// 请假申请,
/// Context--上下文环境,保存业务处理中参数-中间结果-最终结果
/// 行为型设计模式常用的标配
/// 把行为转移,
/// </summary>
public class ApplyContext
{
public int Id { get; set; }
public string Name { get; set; }
/// <summary>
/// 请假时长
/// </summary>
public int Hour { get; set; }
public string Description { get; set; }
public bool AuditResult { get; set; }
public string AuditRemark { get; set; }
}
/// <summary>
/// 职责问题:
/// 1 权限范围内,审批通过
/// 2 权限范围外,交给下一环节审批
/// 写的代码又多了一个,指定下一环节
/// 甩锅大法
/// </summary>
public class PM : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
}
}
}
public class Charge: AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
}
}
}
public class Manager : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
}
}
}
public class Chief : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
//....
}
}
}
public class CEO : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
//....
}
}
}
public class ChiarMan : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit");
if (context.Hour <= )
{
context.AuditResult = true;
context.AuditRemark = "允许请假!";
}
else
{
base.AuditNext(context);
//....
}
}
}
前端调用:
ApplyContext context = new ApplyContext()
{
Id = ,
Name = "aaa",
Hour = ,
Description = "我想...",
AuditResult = false,
AuditRemark = ""
};
//流程的可扩展 AbstractAuditor auditor = AuditorBuilder.Build();
auditor.Audit(context);
if (!context.AuditResult)
{
Console.WriteLine("不干了!");
}
//把流程环节逻辑从业务类转移了
public class AuditorBuilder
{
/// <summary>
/// 那就反射+配置文件
/// 链子的组成都可以通过配置文件
/// </summary>
/// <returns></returns>
public static AbstractAuditor Build()
{
AbstractAuditor pm = new PM()
{
Name = "bbb"
};
AbstractAuditor charge = new Charge()
{
Name = "ccc"
};
AbstractAuditor manager = new Manager()
{
Name = "ddd"
};
AbstractAuditor chief = new Chief()
{
Name = "eee"
};
AbstractAuditor ceo = new CEO()
{
Name = "fff"
}; pm.SetNext(charge);
charge.SetNext(manager);
//pm.SetNext(manager);
manager.SetNext(chief);
chief.SetNext(ceo);
ceo.SetNext(new ChiarMan()
{
Name = "ggg"
});
return pm;
}
}
代码中存在多个if-else语句的情况下,此时可以考虑使用责任链模式来对代码进行重构
本文参考文档:
https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html
https://www.cnblogs.com/zhili/p/ChainOfResponsibity.html
https://www.cnblogs.com/abcdwxc/archive/2007/09/25/905622.html
23种设计模式之责任链模式(Chain of Responsibility Pattern)的更多相关文章
- 二十四种设计模式:责任链模式(Chain of Responsibility Pattern)
责任链模式(Chain of Responsibility Pattern) 介绍为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求.将这些对象连成一条链,并沿着这条链传递该请求,直 ...
- 乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern)
原文:乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 责任链模式(Chain of R ...
- 23种设计模式之责任链模式(Chain of Responsibility)
责任链模式是一种对象的行为型模式,避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止.责任链模式不保证每个请求都被接受, ...
- 【Unity与23种设计模式】责任链模式(Chain of Responsibility)
GoF中定义: "让一群对象都有机会来处理一项请求,以减少请求发送者与接收者之间的耦合度.将所有的接受对象串联起来,让请求沿着串接传递,直到有一个对象可以处理为止." 举个现实中的 ...
- 23种设计模式--责任链模式-Chain of Responsibility Pattern
一.责任链模式的介绍 责任链模式用简单点的话来说,将责任一步一步传下去,这就是责任,想到这个我们可以相当击鼓传花,这个是为了方便记忆,另外就是我们在项目中经常用到的审批流程等这一类的场景时我们就可以考 ...
- C#设计模式-责任链模式(Chain of Responsibility Pattern)
引子 一个事件需要经过多个对象处理是一个挺常见的场景,譬如采购审批流程,请假流程,软件开发中的异常处理流程,web请求处理流程等各种各样的流程,可以考虑使用责任链模式来实现.现在以请假流程为例,一般公 ...
- [设计模式] 13 责任链模式 Chain of Responsibility
转 http://blog.csdn.net/wuzhekai1985 http://www.jellythink.com/archives/878 向项目经理提交了休假申请,我的项目经理向 ...
- 设计模式 笔记 责任链模式 chain of responsibility
//---------------------------15/04/25---------------------------- //Chain of responsibility 责任链----- ...
- 责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)
责任链模式(Chain of Responsibility Pattern) 职责链模式 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系 将这些对象连接成一条链,并沿着这 ...
随机推荐
- linux安装man中文手册并保留英文man手册
大家都知道学习linux系统,查找man手册帮助是非常重要的,然而默认linux的man手册是英文文档,快速阅读英文man固然重要,不过配置好中文man也可以让自己更快速地学习!当然英文学习大家还是不 ...
- Nginx入门(一):在centos上安装nginx
CenterOS7安装Nginx =================== 参考:https://www.xuliangwei.com/bgx/972.html nginx官网下载地址:http://n ...
- Redis数据类型的基本操作
Redis数据类型的基本操作 一.string类型 1.设置value
- hdu 1503 Advanced Fruits 最长公共子序列 *
Advanced Fruits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- 工作中遇到的99%SQL优化,这里都能给你解决方案(二)
-- 示例表 CREATE TABLE `employees` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(24) NOT NULL ...
- Linux 安装二进制MySQL 及 破解MySQL密码
1.确保系统中有依赖的libaio 软件,如果没有: yum -y install libaio 2.解压二进制MySQL软件包 tar xf mysql-5.7.24-linux-glibc2.12 ...
- 059 Python计算生态概览
目录 一.概要 二.导学 三.实践能力 一.概要 从数据处理到人工智能 实例15-霍兰德人格分析雷达图 从Web解析到网络空间 从人机交互到艺术设计 实例16-玫瑰花绘制 二.导学 纵览Python计 ...
- Git使用(二)版本库创建及文件修改
一.创建版本库 1.安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功! 安装完成后,还需要最后一步设置,在命令行输入: $ gi ...
- CXF添加拦截器和自定义拦截器
前面讲了如何采用CXF开发webservice,现在来讲如何添加拦截器和自定义拦截器. 服务端代码: HelloWorld implementor=new HelloWorldImpl(); Stri ...
- SpringCloud超简单的入门(1)--一些简单的介绍
简介 简单来说,springcloud的就是由一组springboot应用(服务)组成,相互之间通过REST等方式进行通信. 两个springboot应用,其中一个作为服务提供者,一个作为服务消费者, ...