使用场景
什么时候应该使用责任链模式?
这种模式最佳的使用场景是,你的业务上有一个逻辑上的处理链,这个处理链每次必须按照顺序运行。这里请注意,链分叉是这种模式的一个变体,
但是很快处理起来就会非常复杂。因此,当我对现实世界中“命令链”场景建模的时候,我通常会使用这种模式。
这就是我以银行为例的原因,因为它就是现实世界中可以用代码建模的“责任链”。
示例
这里假设我们拥有一家银行,银行里面有3个级别的员工,分别是“柜员”、“主管”、“银行经理”。如果有人来取款,“柜员”只允许10,000美元以下的取款操作。
如果金额超过10,000美元,那么它的请求将传递给“主管”。“主管”可以处理不超过100,000美元的请求,但前提是该账户在必须有身份证ID。
如果没有身份证ID,则当前请求必须被拒绝。如果取款金额超过100,000美元,则当前请求可以转交给“银行经理”,“银行经理”可以批准任何取款金额,
因为如果有人取超过100,000美元的金额,他们就是VIP, 我们不在乎VIP的身份证ID和其他规定。
糟糕的实现, if/else地狱
// <summary>
// 糟糕的实现, if/else地狱
// </summary>
class BankAccount
{
bool idOnRecord { get; set; }
void WithdrawMoney(decimal amount)
{
// 柜员处理
if (amount < 10000)
{
Console.WriteLine("柜员提取的金额");
}
// 主管处理
else if (amount < 100000)
{
if (!idOnRecord)
{
throw new Exception("客户没有身份证ID");
}
Console.WriteLine("主管提取的金额");
}
else
{
Console.WriteLine("银行经理提取的金额");
}
}
}
责任链模式实现
/// 什么时候应该使用责任链模式?
/// 这种模式最佳的使用场景是,你的业务上有一个逻辑上的处理链,这个处理链每次必须按照顺序运行。这里请注意,链分叉是这种模式的一个变体,
/// 但是很快处理起来就会非常复杂。因此,当我对现实世界中“命令链”场景建模的时候,我通常会使用这种模式。
/// 这就是我以银行为例的原因,因为它就是现实世界中可以用代码建模的“责任链”。
static class ChainOfResponsibility
{
public static void StartTest()
{
var bankManager = new BankManager();
var bankSupervisor = new Supervisor();
bankSupervisor.SetLineManager(bankManager);
var frontLineStaff = new Teller();
frontLineStaff.SetLineManager(bankSupervisor);
//模拟客户取款,从柜员开始处理取款请求
frontLineStaff.HandleWithdrawRequest(new BankAccount() { idOnRecord = true }, 100000);
}
}
//柜员
class Teller : BankEmployee, IBankEmployee
{
protected override bool CanHandleRequest(BankAccount account, decimal amount)
{
if (amount > 10000)
{
return false;
}
return true;
}
protected override void Withdraw(BankAccount account, decimal amount)
{
Console.WriteLine($"柜员提取了金额,金额为: {amount}");
}
}
//主管
class Supervisor : BankEmployee, IBankEmployee
{
protected override bool CanHandleRequest(BankAccount account, decimal amount)
{
if (amount > 100000)
{
return false;
}
return true;
}
protected override void Withdraw(BankAccount account, decimal amount)
{
if (!account.idOnRecord)
{
throw new Exception("客户没有身份证ID");
}
Console.WriteLine($"主管提取了金额,金额为: {amount}");
}
}
//银行经理
class BankManager : BankEmployee, IBankEmployee
{
protected override bool CanHandleRequest(BankAccount account, decimal amount)
{
return true;
}
protected override void Withdraw(BankAccount account, decimal amount)
{
Console.WriteLine($"银行经理提取了金额,金额为: {amount}");
}
}
/// <summary>
/// 定义银行雇员接口,约束雇员行为,实现多态
/// LineManager: 雇员的上级
/// HandleWithdrawRequest: 处理客户的取款请求
/// </summary>
interface IBankEmployee
{
IBankEmployee LineManager { get; }
void HandleWithdrawRequest(BankAccount account, decimal amount);
}
/// <summary>
/// 定义银行雇员抽象类,实现HandleWithdrawRequest方法,每个实现类都需要使用它,比接口的多态性多了复用的功能
/// SetLineManager(): 设置自身的上级
/// CanHandleRequest抽象方法:判断自身是否能处理客户的取款请求,子类必须实现
/// Withdraw抽象方法:取款方法
/// </summary>
abstract class BankEmployee : IBankEmployee
{
public IBankEmployee LineManager { get; private set; }
public void SetLineManager(IBankEmployee lineManager)
{
this.LineManager = lineManager;
}
public void HandleWithdrawRequest(BankAccount account, decimal amount)
{
if (CanHandleRequest(account, amount))
{
Withdraw(account, amount);
}
else
{
LineManager.HandleWithdrawRequest(account, amount);
}
}
abstract protected bool CanHandleRequest(BankAccount account, decimal amount);
abstract protected void Withdraw(BankAccount account, decimal amount);
}
/// <summary>
/// 银行账号类
/// </summary>
class BankAccount
{
//判断客户是否有身份ID号
public bool idOnRecord { get; set; }
//public void WithdrawMoney(IBankEmployee frontLineStaff, decimal amount)
//{
// frontLineStaff.HandleWithdrawRequest(this, amount);
//}
}