为请求创建了一个接收者对象的链。在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,请求会自动进行传递。所以责任链将请求的发送者和请求的处理者解耦了。
比如请假场景,上级审批不通过,交给上上级审批 责任链模式,客户将请求发送给责任链即可,不需要关注请求的处理过程,将请求的发送者和请求的处理者解耦了。比如请假场景,0-1天主管审批、1-3天科长审批、3-7天经理审批。需要有主管、科长、经理三个类,每个类中有一个审批方法,没有任何设计的话,可能在审批方法中写很多if-else-if这种判断,来交给下一个审批人。但是审批人可能是变化的,比如取消主管职位,我们的类会需要频繁修改,变得不稳定。这时我们可以在类中加一个下一个审批人的属性,和设置下一个审批人的方法,在审批方法中交给下一个审批人,至于下一个审批人是谁,交给上端指定。
ApplyContext代表请假条。
**Context是责任链模式的标配,行为转移到哪儿,context会跟到哪儿
示例:请假流程
public class ApplyContext
{
public int Id { get; set; }
public string? Name { get; set; }
/// <summary>
/// 请假时长
/// </summary>
public int Hour { get; set; }
/// <summary>
/// 请教的描述信息
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 请假是否审批通过
/// </summary>
public bool AuditResult { get; set; }
/// <summary>
/// 审批备注
/// </summary>
public string? AuditRemark { get; set; }
}
请假写法
面向过程写法
//请假条
ApplyContext context = new ApplyContext() //标配---
{
Id = 506,
Name = "Join",
Hour = 30,
Description = "朝夕教育线下沙龙",
AuditResult = false,
AuditRemark = ""
};
{
if (context.Hour <= 8) {
context.AuditResult = true;
context.AuditRemark = "PM审批通过";
}
else {
if (context.Hour < 16) {
context.AuditResult = true;
context.AuditRemark = "主管审批通过";
}
else {
//.... 后续还有很多判断
}
}
}
问题:
完全是面向过程式编程,所有的业务逻辑完全暴露在上端,完全没有任何面向对象的思想(继承--封装--多态)
改进一:面向对象写法
改进一:POP--OOP,改为面向对象编程
- 对象:请假条,PM,Charge,Manager经理
- 确定对象--封装业务逻辑-- - 封装
- 继承去掉重复代码-- - 继承
- 统一类下的同一个方法执行的不同的业务逻辑----多态
public class PM
{
public int Id { get; set; }
public string? Name { get; set; }
//审批动作
public void Audit(ApplyContext context)
{
if (context.Hour <= 8)
{
context.AuditResult = true;
context.AuditRemark = "PM审批通过";
}
else
{
//...
}
}
}
public class Charge
{
public int Id { get; set; }
public string? Name { get; set; }
public void Audit(ApplyContext context)
{
if (context.Hour <= 16)
{
context.AuditResult = true;
context.AuditRemark = "主管审批通过";
}
else
{
//...
}
}
}
2、抽象出父类,子类继承父类
public abstract class AbstractAuditor
{
public int Id { get; set; }
public string? Name { get; set; }
public abstract void Audit(ApplyContext context);
}
子类
public class PM : AbstractAuditor
{
//审批动作
public override void Audit(ApplyContext context)
{
if (context.Hour <= 8)
{
context.AuditResult = true;
context.AuditRemark = "PM审批通过";
}
else
{
//...
}
}
}
public class Charge : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
if (context.Hour <= 16)
{
context.AuditResult = true;
context.AuditRemark = "主管审批通过";
}
else
{
//...
}
}
}
上端调用
//子类继承父类,可以使用父类去声明一个子类
{
AbstractAuditor pm = new PM() {
Id = 123,
Name = "小黄鱼"
};
pm.Audit(context);
if (!context.AuditResult) {
AbstractAuditor charge = new Charge() //自己去找主管
{
Id = 234,
Name = "1同学"
};
charge.Audit(context);
}
}
代码其实不符合业务逻辑。
正确的业务逻辑应该是 请假者--提交请假条给PM--PM能审批通过就通过了,如果不能审批通过。应该由PM自动转交给主管。
改进二:向实体类添加业务逻辑
public class PM : AbstractAuditor
{
//审批动作
public override void Audit(ApplyContext context)
{
if (context.Hour <= 8)
{
context.AuditResult = true;
context.AuditRemark = "PM审批通过";
}
else
{
//自动转交给主管...
AbstractAuditor charge = new Charge()
{
Id = 234,
Name = "1同学"
};
charge.Audit(context);
}
}
}
public class Charge : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
if (context.Hour <= 16)
{
context.AuditResult = true;
context.AuditRemark = "主管审批通过";
}
else
{
//自动转交给经理...
AbstractAuditor manager = new Manager() {
Id = 456,
Name = "Join"
};
manager.Audit(context);
}
}
}
public class Manager : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
if (context.Hour <= 32)
{
context.AuditResult = true;
context.AuditRemark = "经理审批通过";
}
else
{
//...
}
}
}
上端调用
{
AbstractAuditor pm = new PM() {
Id = 123,
Name = "小黄鱼"
};
pm.Audit(context);
}
分析:
开发的功能只是符合了当前的业务需求。没有考虑到将来可能会发生什么变化。
比如组织架构发生改变:主管的职位,不要主管的这个职位了。必须要修改之前的代码,这就违背了开闭原则。代码的不稳定,就要想办法让代码稳定。
改进三:将流程中可配置部分甩锅出去
public class PM : AbstractAuditor
{
private AbstractAuditor _NextAuditor;
//设置下一个审批者
public void SetNextAuditor(AbstractAuditor nextAuditor) {
this._NextAuditor = nextAuditor;
}
//审批动作
public override void Audit(ApplyContext context)
{
if (context.Hour <= 8)
{
context.AuditResult = true;
context.AuditRemark = "PM审批通过";
}
else
{
//这里可能会代码不稳定,这个锅,我不背---甩锅给别人。让别人来背过。
//不能写死~--甩锅出去
_NextAuditor?.Audit(context);
}
}
}
public class Charge : AbstractAuditor
{
private AbstractAuditor _NextAuditor;
//设置下一个审批者
public void SetNextAuditor(AbstractAuditor nextAuditor) {
this._NextAuditor = nextAuditor;
}
public override void Audit(ApplyContext context)
{
if (context.Hour <= 16)
{
context.AuditResult = true;
context.AuditRemark = "主管审批通过";
}
else
{
//甩锅出去
_NextAuditor?.Audit(context);
}
}
}
public class Manager : AbstractAuditor
{
private AbstractAuditor _NextAuditor;
//设置下一个审批者
public void SetNextAuditor(AbstractAuditor nextAuditor) {
this._NextAuditor = nextAuditor;
}
public override void Audit(ApplyContext context)
{
if (context.Hour <= 32)
{
context.AuditResult = true;
context.AuditRemark = "经理审批通过";
}
else
{
//甩锅出去
_NextAuditor?.Audit(context);
}
}
}
抽取到公共父类
public abstract class AbstractAuditor
{
public int Id { get; set; }
public string? Name { get; set; }
public abstract void Audit(ApplyContext context);
protected AbstractAuditor _NextAuditor;
/// <summary>
/// 设置下一个审批者
/// </summary>
public void SetNextAuditor(AbstractAuditor nextAuditor)
{
this._NextAuditor = nextAuditor;
}
}
实现父类的子类
public class PM : AbstractAuditor
{
//审批动作
public override void Audit(ApplyContext context)
{
if (context.Hour <= 8)
{
context.AuditResult = true;
context.AuditRemark = "PM审批通过";
}
else
{
//这里可能会代码不稳定,这个锅,我不背---甩锅给别人。让别人来背过。
//不能写死~--甩锅出去
_NextAuditor?.Audit(context);
}
}
}
public class Charge : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
if (context.Hour <= 16)
{
context.AuditResult = true;
context.AuditRemark = "主管审批通过";
}
else
{
//甩锅出去
_NextAuditor?.Audit(context);
}
}
}
public class Manager : AbstractAuditor
{
public override void Audit(ApplyContext context)
{
if (context.Hour <= 32)
{
context.AuditResult = true;
context.AuditRemark = "经理审批通过";
}
else
{
//甩锅出去
_NextAuditor?.Audit(context);
}
}
}
上端调用
AbstractAuditor pm = new PM()
{
Id = 123,
Name = "小黄鱼"
};
AbstractAuditor charge = new Charge() {
Id = 234,
Name = "1同学"
};
AbstractAuditor manager = new Manager()
{
Id = 345,
Name = "join"
};
pm.SetNextAuditor(manager);
charge.SetNextAuditor(manager);
pm.Audit(context);
甩锅后:
1.需要上端来配置审批流程。可以灵活配置审批环节
2.如果组织架构发生变化了,如取消主管的职位。修改装配环节即可
3.上端的代码变复杂了,但有办法解决的。-要另外的设计模式来协助解决,建造者模式
改进四:建造者模式解决上端代码复杂
AbstractAuditor pm = new PM()
{
Id = 123,
Name = "小黄鱼"
};
AbstractAuditor charge = new Charge() {
Id = 234,
Name = "1同学"
};
AbstractAuditor manager = new Manager()
{
Id = 345,
Name = "join"
};
pm.SetNextAuditor(manager);
charge.SetNextAuditor(manager);
return pm
上端调用