通俗易懂设计模式解析——责任链模式

前言

  今天咱们介绍的是责任链模式【Chain of Responsibility Pattern】。对于责任链模式理解起来仍是比较容易的。例如在公司请假、三天之内部门经理批准便可,可是三到七天可能就须要总监批准了、七天以上须要副总裁批准。对于这么一个需求最初的解决方案就是if-else语句判断。可是 一旦请假的模式增长一种则须要对多重if-else进行修改,这就违背了开闭原则。这个时候就能够采用责任链模式来解决其问题。责任链模式为请求建立一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。html

责任链模式介绍

1、来由

  在软件系统中,常常会有一个请求可能会被多个对象处理。可是每一次都是被一个对象处理。又不能肯定是哪个对象。若是显示指定每个对象。会对请求发送者和接收者形成紧耦合。那么如何作到对请求的发送者和接收者进行解耦。而且在运行时自行决定处理请求的对象呢?设计模式

2、意图

  避免请求发送者与接收者耦合在一块儿,让多个对象都有可能接收请求,将这些对象链接成一条链,而且沿着这条链传递请求,直到有对象处理它为止。ide

3、案例

 

4、责任链模式代码示例

看上述案例图,主要涉及到两个部分:性能

  抽象处理者:定义一个处理请求的接口this

  具体处理者:实现处理请求的接口、能够选择是本身处理或者传递给下一个接收者。包含对下一个接收处理者的引用。spa

责任链模式的组成部分仍是比较简单的。咱们看这么一个案例,仍是用户结算时金额计算的案例。根据用户的会员等级进行对应的折扣结算。普通用户全额计算、普通会员95折计算、黄金会员9折计算、钻石会员7折计算:设计

  咱们首先看看不使用责任链模式如何处理:code

namespace ChainofResponsibility_Pattern { class Program { static void Main(string[] args) { decimal Money = 200M; var memberType = MemberType.GoldMember; //普通会员,95折计算
            if (memberType == MemberType.Member) { Console.WriteLine($"普通会员,95折计算,最后金额为{Money * 0.95M}"); } //黄金会员,9折计算
            else if (memberType == MemberType.GoldMember) { Console.WriteLine($"黄金会员,9折计算,最后金额为{Money * 0.9M}"); } //钻石会员,7折计算
            else if (memberType == MemberType.DiamondsMember) { Console.WriteLine($"钻石会员,7折计算,最后金额为{Money * 0.7M}"); } //无会员,全额计算
            else { Console.WriteLine($"无会员,全额计算,最后金额为{Money}"); } } public enum MemberType { [Description("无会员")] NoMember = 1, [Description("普通会员")] Member = 2, [Description("黄金会员")] GoldMember = 3, [Description("钻石会员")] DiamondsMember = 4 } } } 

   这里咱们能够看到咱们使用了多个if条件判断完成的此需求(或者switch语句)。这里咱们增长一种会员方式或者优惠折扣都是直接对条件语句进行修改的。或者某个会员的折扣进行了修改都须要对条件进行修改。这里请求的发送者和接收者具备紧耦合。而且多个if条件加在一块儿,不易于判断及理解。htm

  咱们再看看使用责任链模式:对象

namespace ChainofResponsibility_Pattern
{
    public enum MemberType 
    {
        [Description("无会员")]
        NoMember=1,
        [Description("普通会员")]
        Member =2,
        [Description("黄金会员")]
        GoldMember =3,
        [Description("钻石会员")]
        DiamondsMember =4

    }
    class ChainofResponsibilityPattern
    {
    }

    /// <summary>
    /// 结算请求
    /// </summary>
    public class SettlementRequest
    {
        /// <summary>
        /// 金额
        /// </summary>
        public decimal _money;
        /// <summary>
        /// 会员类型
        /// </summary>
        public MemberType _memberType;
        public SettlementRequest(decimal money,MemberType memberType) 
        {
            this._money = money;
            this._memberType = memberType;
        }
    }

    /// <summary>
    /// 结算抽象处理
    /// </summary>
    public abstract class SettlementHandler 
    {
        /// <summary>
        /// 下一位接收处理者
        /// </summary>
        public SettlementHandler nextHandler;
        public abstract void Settlement(SettlementRequest settlementRequest); 
    }

    /// <summary>
    /// 无会员接收者
    /// </summary>
    public class NoMemberHandler : SettlementHandler
    {
        public override void Settlement(SettlementRequest settlementRequest)
        {
            if (settlementRequest._memberType==MemberType.NoMember)
            {
                Console.WriteLine($"无会员,不进行折扣计算。最后金额为{settlementRequest._money}");
            }
            else
            {
                nextHandler.Settlement(settlementRequest);
            }
        }
    }

    /// <summary>
    /// 普通会员接收处理者
    /// </summary>
    public class  MemberHandler : SettlementHandler
    {
        public override void Settlement(SettlementRequest settlementRequest)
        {
            if (settlementRequest._memberType == MemberType.Member)
            {
                Console.WriteLine($"普通会员,95折计算。最后金额为{settlementRequest._money*0.9M}");
            }
            else
            {
                nextHandler.Settlement(settlementRequest);
            }
        }
    }

    /// <summary>
    /// 黄金会员接收处理者
    /// </summary>
    public class GoldMemberHandler : SettlementHandler
    {
        public override void Settlement(SettlementRequest settlementRequest)
        {
            if (settlementRequest._memberType == MemberType.GoldMember)
            {
                Console.WriteLine($"黄金会员,9折计算。最后金额为{settlementRequest._money*0.9M}");
            }
            else
            {
                nextHandler.Settlement(settlementRequest);
            }
        }
    }

    /// <summary>
    /// 钻石会员接收处理者
    /// </summary>
    public class DiamondsMemberHandler : SettlementHandler
    {
        public override void Settlement(SettlementRequest settlementRequest)
        {
            if (settlementRequest._memberType == MemberType.DiamondsMember)
            {
                Console.WriteLine($"钻石会员,7折计算。最后金额为{settlementRequest._money*0.7M}");
            }
            else
            {
                nextHandler.Settlement(settlementRequest);
            }
        }
    }
}

 

namespace ChainofResponsibility_Pattern
{
    class Program
    {
        static void Main(string[] args)
        {
            ///设置请求
            SettlementRequest settlementRequest = new SettlementRequest(200, MemberType.GoldMember);

            ///初始化具体处理
            SettlementHandler NoMember = new NoMemberHandler();
            SettlementHandler Member = new MemberHandler();
            SettlementHandler GoldMember = new GoldMemberHandler();
            SettlementHandler DiamondsMember = new DiamondsMemberHandler();

            ///设置责任链
            NoMember.nextHandler = Member;
            Member.nextHandler = GoldMember;
            GoldMember.nextHandler = DiamondsMember;

            ///处理请求
            NoMember.Settlement(settlementRequest);
        } 
    }
} 

  这里咱们将会员判断及计算细化到了不一样的类中。每个类都仅针对他本身的会员折扣进行计算。咱们增长会员模式也仅须要增长一个具体处理类而且重建责任链便可。若是修改某个会员的对应折扣也仅修改对应的类便可。咱们看下面的运行结果和上面的也是同样的。

使用场景及优缺点

1、使用场景

一、有多个对象处理同一个请求,具体哪个对象处理在运行时自行肯定

二、在不明白具体接收者的状况下,向多个对象中的一个提交请求

三、代码块中存在多个if-else语句的状况下,能够考虑使用责任链模式进行重构

四、一个系统的审批须要多个对象才能完成处理。例如请假系统或者采购模块。

2、优势

一、下降请求发送者和接收者之间的耦合度

二、简化了对象、使对象不清除链的结构

三、增长了对象指派职责的灵活度、加强了可扩展性

四、将多个条件语句进行分散到各个具体处理类中,增长代码的可阅读性。使代码更加清晰,责任更明确

3、缺点

一、在未找到请求接收者以前会对多有对象执行一遍,若是责任链过长会对性能形成必定影响

二、可能致使某一个请求不被处理

三、可能不太容易进行错误排查

四、容易形成循环调用

总结

  责任链模式主要下降了请求发送者和接收者之间的耦合度。使得多个对象都有机会处理某一个请求。在请假系统中可能须要多我的物对请假进行审批。采购系统中可能须要不一样高度的人进行审批。一个请求可能由多个对象处理,可是不清楚具体接收者对象。因此将对象连成一条链子,使请求沿着这条链子传递下去。直到被处理为止、这就是责任链模式。


    即便受伤了,也要抬起头微笑着说,今每天气真好。

    C#设计模式系列目录

      欢迎你们扫描下方二维码,和我一块儿踏上设计模式的闯关之路吧!

  

相关文章
相关标签/搜索