行为型模式之责任链模式

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给与请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行为型模式
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

简单用图表示一下:
在这里插入图片描述

场景

公司中的某个员工小A最近表现很好,工作努力、解决问题效率高,所以小A想提出涨工资的要求。但是公司的管理序列负责,该怎么办?
首先,小A找到了直属部门经理,但是部门经理说我没有权限。
接下来,小A去找部门总监,同样部门总监也说没有权限;
最后,小A辗转找到了总经理,总经理经过认真考察,同意了A的请求。

仔细分析上面的场景,当A提出涨薪的申请时,后续处理这个申请的对象,部门经理,部门总监,总经理,自然的形成了一个链,从部门经理-部门总监-总经理,客户端的申请请求就在这个链中传递,直到有领导处理为止。看起来,上面的功能要求很适合采用职责链来处理这个业务。

要想处理请求的流程可以灵活的变动,一个基本思路,那就是动态构建流程步骤,这样随时都可以重新组合新的流程来.而要让处理请求的对象也要很灵活,那就要让它足够简单,最好是只实现单一的功能,或者是有限的功能,这样更有利于修改和复用。

为什么动态构建还要单一呢?比如现在A提出的申请,直接先找部门总监,完了再看总经理,没有部门经理什么事,他压根不参与,之前的逻辑你就要重新修改.或者审批不但只是通过不通过,还要加上每个处理对象对涨薪的多少有决定,那处理的逻辑也变了.所以上面要求构建流程要动态并且单一

责任链模式就很好的体现了上述的基本思路,那么它是怎么做的呢

  • 首先责任链模式会定义一个所以处理请求的对象都要继承实现的抽象类,这样就有利于随时切换新的实现;
  • 其次每个处理请求对象只实现业务流程中的一步业务处理,这样使其变得简单
  • 最后责任链模式会动态的来组合这些处理请求的对象,把他们按照流程动态组合起来,并要求它们依次调用,这样就动态的实现了流程

这样一来,如果流程发生了变化,只要重新组合就好了;如果某个处理的业务功能发生了变化,一个方案是修改该处理对应的处理对象,另一个方案是直接提供一个新的实现,然后在组合流程的时候,用新的实现替换掉旧的实现就可以了。

在iOS中,最典型的例子就是UIView对事件处理的响应函数
在这里插入图片描述

模式结构和说明

在这里插入图片描述

Handler:定义职责的接口,通常在这里定义处理请求的方法,可以在这里实现后继链。
ConcreteHandler:实现职责的类,在这个类里面,实现对在它职责范围内请求的处理,如果不处理,就继续转发请求给后继者。
Client:职责链的客户端,向链上的具体处理者对象提交请求,让职责链负责处理。

示例代码

用责任链模式来重写场景示例,功能:当某人提出涨薪后,该请求会在部门经理-部门总监-总经理这样一条领导处理链上进行传递,发出请求的人并不知道谁来处理他的请求,每个领导会根据自己的职责范围,来判断是处理请求还是把请求交给更高级的领导,只要有领导处理了,传递就结束了

需要把每位领导的处理独立出来,实现成单独的职责处理对象,然后为它们提供一个公共的、抽象的父职责对象,这样就可以在客户端来动态的组合职责链,实现不同的功能要求了

  1. 定义职责的抽象类,在这个类里面持有下一个处理请求的对象,同时还要定义业务处理方法
//抽象类
@interface Manager : NSObject
/*下一个处理请求的对象*/
@property (nonatomic,strong) Manager *nextManager;

- (void)handleRequest:(NSString *)user salary:(float)salary;

@end
  1. 具体处理者类(部门经理、部门总监、总经理)
//部门经理
@implementation DepartmentManager

- (void)handleRequest:(NSString *)user salary:(float)salary
{
    if (salary <= 500) {
        NSLog(@"%@ 处理了%@涨薪%.2f的请求",NSStringFromClass([self class]),user,salary);
    } else {
        NSLog(@"%@ 无权处理%@涨薪%.2f的请求",NSStringFromClass([self class]),user,salary);
        [self.nextManager handleRequest:user salary:salary];
    }
}
@end
//部门总监
@implementation DepartmentDirector
- (void)handleRequest:(NSString *)user salary:(float)salary
{
    if (salary > 500 && salary <= 1000) {
        NSLog(@"%@ 处理了%@涨薪%.2f的请求",NSStringFromClass([self class]),user,salary);
    } else {
        NSLog(@"%@ 无权处理%@涨薪%.2f的请求",NSStringFromClass([self class]),user,salary);
        [self.nextManager handleRequest:user salary:salary];
    }
}
@end
//总经理
@implementation GeneralManager

- (void)handleRequest:(NSString *)user salary:(float)salary
{
    if (salary > 1000 && salary <= 3000) {
        NSLog(@"%@ 处理了%@涨薪%.2f的请求",NSStringFromClass([self class]),user,salary);
    } else {
        NSLog(@"%@你咋涨这么多薪资呢?没法批",NSStringFromClass([self class]));
    }
}
@end
  1. 客户端使用
    Manager *dm = [[DepartmentManager alloc] init];
    Manager *dd = [[DepartmentDirector alloc] init];
    Manager *gm = [[GeneralManager alloc] init];
    
    dm.nextManager = dd;
    dd.nextManager = gm;
    
    [dm handleRequest:@"张三" salary:300];
    [dm handleRequest:@"刘伟" salary:800];
    [dm handleRequest:@"李四" salary:2000];
    [dm handleRequest:@"王五" salary:5000];
  1. 结果
    在这里插入图片描述

模式讲解

1. 认识责任链模式

模式功能

职责链模式主要用来处理:“客户端发出一个请求,有多个对象都有机会来处理这一个请求,但是客户端不知道究竟谁会来处理他的请求”,这样的情况。也就是需要让请求者和接收者解耦,这样就可以动态的切换和组合接收者了

在标准的职责链模式里面,是只要没有有对象处理了请求,这个请求就到此为止,不再被传递和处理了。

隐式接受者

当客户端发出请求的时候,客户端并不知道谁会真正处理他的请求,客户端只知道他提交请求的第一个对象。从第一个处理对象开始,整个职责链里面的对象,要么自己处理请求,要么继续转发给下一个接收者。
也就是对于请求者而言,并不知道最终的接收者是谁,但是一般情况下,总是会有一个对象来处理的,因此称为隐式接收者。

谁来处理

职责链中那么多处理对象,到底谁来处理请求呢,这个是在运行时期动态决定的。当请求被传递到某个处理对象的时候,这个对象会按照已经设定好的条件来判断,是否属于自己处理的范围,如果是就处理,如果不是就转发请求给下一个对象。

当然,在职责链模式中,请求不一定会被处理,因为可能没有合适的处理者,请求在职责链里面从头传递到尾,每个处理对象都判断不属于自己处理,最后请求就没有对象来处理。

2. 处理多种请求

前面的示例都是同事职责链处理一种请求的情况,现在有这样得需求,A除了想涨薪资外,还想换个岗位,假设还是同一流程,也就是说还是同一责任链,虽然流程相同,但是每个处理类需要处理两种请求,它们的具体业务逻辑是不一样的,那么该如何实现呢?

有两种方式:

  • 为每种业务单独定义一个方法,然后客户端根据不同的需要调用不同的方法
//抽象类
@interface Manager : NSObject
/*下一个处理请求的对象*/
@property (nonatomic,strong) Manager *nextManager;
//调薪业务
- (void)handleRequest:(NSString *)user salary:(float)salary;
//换岗位业务
- (void)handleChangePosition:(NSString *)user;

@end

实现上很容易,但有一个很明显的问题,那就是只要增加一个业务,就需要修改职责接口,这是很不灵活的,在编程中强调面向接口编程,因此接口应该相对保持稳定,接口一改,需要修改的地方就太多了,频繁修改接口绝对不是个好主意。

那有没有什么好方法来实现呢?分析一下现在变化的东西:

一是不同的业务需要传递的业务数据不同;
二是不同的业务请求的方法不同;
三是不同的职责对象处理这些不同的业务请求的业务逻辑不同;

那么怎么解决呢,就是下面的第二种方法

  • 首先定义一套通用的调用框架,用一个通用的请求对象来封装请求传递的参数;然后定义一个通用的调用方法,这个方法不去区分具体业务,所有的业务都是这一个方法,那么具体的业务如何区分呢,就是在通用的请求对象里面会有一个业务的标记;到了职责对象里面,愿意处理就跟原来一样的处理方式,如果不愿意处理,就传递到下一个处理对象就好了。
@interface RequestModel : NSObject
/*业务类型(根据需求而定)*/
@property (nonatomic,assign) NSInteger type;

@end
//抽象类
@interface Manager : NSObject

#pragma mark - 多请求处理方式二(具体的业务处理在子类根据model的type去判断处理)
- (void)handleRequest:(RequestModel *)model;

3. 优缺点

优点

  • 职责链模式使得一个对象无须知道是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度。
  • 请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接。
  • 在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。
  • 在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看是符合“开闭原则”的。

缺点

  • 因为一个请求没有明确的接收者,该请求可能一直到链的末端都得不到处理;一个请求也可能因职责链没有被正确配置而得不到处理。
  • 对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。
  • 如果建链不当,可能会造成循环调用,将导致系统陷入死循环。

Demo地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
校园失物招领系统管理系统按照操作主体分为管理员和用户。管理员的功能包括字典管理、论坛管理、公告信息管理、失物招领管理、失物认领管理、寻物启示管理、寻物认领管理、用户管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 校园失物招领系统管理系统可以提高校园失物招领系统信息管理问题的解决效率,优化校园失物招领系统信息处理流程,保证校园失物招领系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 ,管理员权限操作的功能包括管理公告,管理校园失物招领系统信息,包括失物招领管理,培训管理,寻物启事管理,薪资管理等,可以管理公告。 失物招领管理界面,管理员在失物招领管理界面中可以对界面中显示,可以对失物招领信息的失物招领状态进行查看,可以添加新的失物招领信息等。寻物启事管理界面,管理员在寻物启事管理界面中查看寻物启事种类信息,寻物启事描述信息,新增寻物启事信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类管理界面,管理员在公告类管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值