【愚公系列】2021年12月 二十三种设计模式(十三)-职责链模式(Chain of Responsibility Pattern)

简介: 【愚公系列】2021年12月 二十三种设计模式(十三)-职责链模式(Chain of Responsibility Pattern)

文章目录

前言

一、职责链模式(Chain of Responsibility Pattern)

二、使用步骤

角色

示例

总结

优点

缺点

使用场景

前言

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。


提示:以下是本篇文章正文内容,下面案例可供参考


一、职责链模式(Chain of Responsibility Pattern)

职责链模式属于行为型模式,它为请求创建了一个接收者对象的链。这种模式给予一个具体请求的类型,对请求的发送者和接收者进行解耦。


通常有2种方法来实现该模式。第1种是每个接收者都包含对下一个接收者的引用,以便在不能处理该请求时,转派请求至下一个接收者。第2个方法是引入中间链条类,由中间件负责转派请求。第一种方法的实现较为简单,本例采用第2种实现方式。


二、使用步骤

角色

1、抽象处理者(Handler)


定义出一个处理请求的接口。接口可以定义出一个方法以设定和返回对链条中下一个处理者的引用,如果使用第2种方式实现,可无需引用下一个处理者,统一由中间件负责;


2、具体处理者(Concrete Handler)


具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家;


3、请求类(Request)


处理者需要处理的请求信息;


4、中间链条类(Chain)


若使用第2种方式实现,则需要引入此中间类,内部维护所有处理者,并在需要时自动转派请求至下一个处理者。


示例

image.png

命名空间ChainOfResponsibility包含领导Leader类充当处理者基类,它包含4个实现类,经理类Manager、总监类Inspector、总经理类President和董事Directorate类,请假信息LeaveRequest类充当请求类,LeaderChain类充当中间链条类。本案例尝试以员工请假来解释职责链模式在审批环节的应用。

public class LeaveRequest {
    public int Days { get; set; }
    public string Name { get; set; }
    public LeaveRequest(int days, string name) {
        Days = days;
        Name = name;
    }
}

请假请求LeaveRequest类,包含需要请假的天数和员工的姓名。一个公开的构造函数表明调用方必须提供请假天数和员工姓名信息。

public abstract class Leader {
    protected string Name { get; set; }
    protected Leader(string name) {
        this.Name = name;
    }
    public static LeaderChain Chain { protected get; set; }
    public abstract void ProcessRequest(LeaveRequest request);
    protected void Delivery(LeaveRequest request) {
        Chain.DoChain(request);
    }
}

领导者Leader类,充当处理者基类,包含领导的姓名Name并维持对中间链的引用。ProcessRequest为处理请假的抽象方法,为处理请假公开了一个调用接口。Delivery则为在不能处理请求时转派至下一个处理者。

public class Manager : Leader {
    public Manager(string name) : base(name) { }
    public override void ProcessRequest(LeaveRequest request) {
        if (request.Days <= 2) {
            Console.WriteLine($"{this.Name} approved {request.Name}'s " +
                                $"leave request for {request.Days} days!");
            return;
        }
        Delivery(request);
    }
}

具体处理者,经理Manager类,如果员工的请假天数小于等于2天,则经理有权限批准该请假请求。

public class Inspector : Leader {
    public Inspector(string name) : base(name) { }
    public override void ProcessRequest(LeaveRequest request) {
        if (request.Days <= 4) {
            Console.WriteLine($"{this.Name} approved {request.Name}'s " +
                                $"leave request for {request.Days} days!");
            return;
        }
        Delivery(request);
    }
}

具体处理者,总监Inspector类,如果员工的请假天数小于等于4天,则总监有权限批准该请假请求。

public class President : Leader {
    public President(string name) : base(name) { }
    public override void ProcessRequest(LeaveRequest request) {
        if (request.Days <= 8) {
            Console.WriteLine($"{this.Name} approved {request.Name}'s " +
                                $"leave request for {request.Days} days!");
            return;
        }
        Delivery(request);
    }
}

具体处理者,总经理President类,如果员工的请假天数小于等于8天,则总经理有权限批准该请假请求。

public class Directorate : Leader {
    public Directorate(string name) : base(name) { }
    public override void ProcessRequest(LeaveRequest request) {
        if (request.Days > 8) {
            Console.WriteLine($"{this.Name} approved {request.Name}'s " +
                                $"leave request for {request.Days} days!");
            return;
        }
        Delivery(request);
    }
}

具体处理者,董事Directorate类,如果员工的请假天数大于8天,则需要董事会批准该请假请求。

public class LeaderChain {
    private List<Leader> _leaders = new List<Leader>();
    private int _cursor = 0;
    public void Attach(Leader leader) {
        if (leader == null) throw new ArgumentNullException();
        _leaders.Add(leader);
    }
    public bool Detach(Leader leader) {
        if (leader == null) throw new ArgumentNullException();
        return _leaders.Remove(leader);
    }
    public void DoChain(LeaveRequest request) {
        if (_cursor <= _leaders.Count - 2) {
            _leaders[++_cursor].ProcessRequest(request);
        }
        _cursor = 0;
    }
}


中间链条类LeaderChain,首先内部维持对所有处理者的引用,包含的游标_cursor指示链条所处的位置,Attach和Detach方法分别向链条中增加和删除处理者。而DoChain方法则真正转派请求至下一个处理者。


此处需要注意的是,由于请求信息是由第一个处理者直接调用的,所以初始游标位置为0并且在DoChain方法中使用++_cursor作为处理者列表的索引参数。也就是说当第一次转派请求时,索引的值为1(因为使用了++_cursor),即为链条中的第2个处理者。请各位看官仔细思考此处逻辑

public class Program {
    public static void Main(string[] args) {
        var leaders = new List<Leader>{
            new Manager("Tom"),
            new Inspector("Juice"),
            new President("Iori"),
            new Directorate("Marin")
        };
        var chain = new LeaderChain();
        foreach (var leader in leaders) {
            chain.Attach(leader);
        }
        Leader.Chain = chain;
        var requests = new List<LeaveRequest> {
            new LeaveRequest(1, "Zhao"),
            new LeaveRequest(3, "Qian"),
            new LeaveRequest(5, "Sun"),
            new LeaveRequest(7, "Li"),
            new LeaveRequest(12, "Zhou")
        };
        foreach (var request in requests) {
            leaders[0].ProcessRequest(request);
        }
        Console.ReadKey();
    }
}

以上为调用方代码的示例,首初始化一个处理者列表并增加至中间链条类,之后模拟“赵、钱、孙、李、周”5位同学的请假请求,他们分别要请1、3、5、7、12天假,最后调用ProcessRequest处理请求。以下是这个案例的输出结果:

Tom approved Zhao's leave request for 1 days!
Juice approved Qian's leave request for 3 days!
Iori approved Sun's leave request for 5 days!
Iori approved Li's leave request for 7 days!
Marin approved Zhou's leave request for 12 days!

总结

优点

1、降低耦合度,它将请求的发送者和接收者解耦;

2、简化了对象,使得对象不需要知道链的结构;

3、增强给对象指派职责的灵活性,通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任;

4、增加新的请求处理者类很方便。


缺点

1、不能保证请求一定被接收;

2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用;

3、可能不容易观察运行时的特征,不利于程序的调试。


使用场景

1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时确定;

2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;

3、需要动态指定一组对象处理请求。


相关文章
|
4月前
|
设计模式 JavaScript 前端开发
js设计模式【详解】—— 职责链模式
js设计模式【详解】—— 职责链模式
76 8
|
2月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
2月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
5月前
|
设计模式
职责链模式-大话设计模式
职责链模式-大话设计模式
|
5月前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)
|
6月前
|
设计模式 安全 Java
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
该文介绍了一种C++的编程技巧——奇异递归模板模式(CRTP),旨在让派生组件能继承基本组件的特定功能。通过示例展示了如何创建一个`Fighter`接口和`MmaFighter`类,其中`MmaFighter`及其子类如`MmaBantamweightFighter`和`MmaHeavyweightFighter`强制类型安全,确保相同重量级的拳手之间才能进行比赛。这种设计避免了不同重量级拳手间的错误匹配,编译时会报错。CRTP适用于处理类型冲突、参数化类方法和限制方法只对相同类型实例生效的情况。
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
|
6月前
|
设计模式 安全 Java
设计模式之责任链 Chain Of Responsibility
设计模式之责任链 Chain Of Responsibility
40 1
|
5月前
|
设计模式
行为设计模式之职责链模式
行为设计模式之职责链模式
|
17天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
2月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。