美文网首页
iOS设计模式之职责链模式

iOS设计模式之职责链模式

作者: 点滴86 | 来源:发表于2024-06-24 00:25 被阅读0次

职责链模式

职责链模式的英文是Chain Of Responsibility Design Pattern。将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。
这职责链模式中,多个处理器(也就是刚刚定义中说的”接收对象“)依次处理同一个请求。一个请求先经过A处理器处理,然后再把请求传递给B处理器,B处理器处理完后再传递给C处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。
职责链模式第一种实现方式如下。其中DMHandler是所有处理器类的父类,每个具体的处理器类(DMHandlerA、DMHandlerB)的- (BOOL)handle 方法的代码结构类似,如果它能处理请求,就不继续往下传递;如果不能处理,则交由后面的处理器来处理(也就是调用[self.successor handle])。DMHandlerChain是处理器链,从数据结构的角度来看,它就是一个记录链头、链尾的链表。其中,记录链尾是为了方便添加处理器。

@protocol DMHandlerDelegate <NSObject>

- (BOOL)handle;

@end

@interface DMHandler : NSObject <DMHandlerDelegate>

@property (nonatomic, strong) DMHandler *successor;

// 子类需要重写
- (BOOL)handle;

@end

@implementation DMHandler

// 子类需要重写
- (BOOL)handle
{
    BOOL bFlag = NO;
    
    return bFlag;
}

@end

@interface DMHandlerA : DMHandler

@end

@implementation DMHandlerA

- (BOOL)handle
{
    BOOL bFlag = NO;
    
    NSLog(@"%@:%@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    // 处理...
    if (self.successor && bFlag == NO) {
        [self.successor handle];
    }
    
    return bFlag;
}

@end

@interface DMHandlerB : DMHandler

@end

- (BOOL)handle
{
    BOOL bFlag = NO;
    NSLog(@"%@:%@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    // 处理...
    if (self.successor && bFlag == NO) {
        [self.successor handle];
    }
    
    return bFlag;
}

@end

@interface DMHandlerChain : NSObject

- (void)addHandler:(DMHandler *)handler;

- (void)handle;

@end

@interface DMHandlerChain ()

@property (nonatomic, strong) DMHandler *head;

@property (nonatomic, strong) DMHandler *tail;

@end

@implementation DMHandlerChain

- (void)addHandler:(DMHandler *)handler
{
    if (self.head == nil) {
        self.head = handler;
        self.tail = handler;
    }
    
    self.tail.successor = handler;
}

- (void)handle
{
    [self.head handle];
}

@end

// 使用举例
- (void)testChain
{
    DMHandlerChain *handlerChain = [[DMHandlerChain alloc] init];
    DMHandlerA *handlerA = [[DMHandlerA alloc] init];
    [handlerChain addHandler:handlerA];
    
    DMHandlerB *handlerB = [[DMHandlerB alloc] init];
    [handlerChain addHandler:handlerB];
    
    [handlerChain handle];
}

实际上,上面的代码实现不够优雅。处理器类的- (BOOL)handle 方法,不仅包含自己的业务逻辑,还包含对下一个处理器的调用,也就是代码中的[self.successor handle]。一个不熟悉这种代码结构的程序员,在添加新的处理器类的时候,很可能忘记在- (BOOL)handle 方法中调用 [self.successor handle] ,这就会导致代码出现bug。
针对这个问题,对代码进行重构,利用模板模式,将调用 [self.successor handle] 的逻辑从具体的处理器类中剥离出来,放到父类中。这样具体的处理器类只需要实现自己的业务逻辑就可以了。重构之后的代码如下所示:

@interface DMHandler : NSObject

@property (nonatomic, strong) DMHandler *successor;

- (void)handle;

// 子类需要重写
- (BOOL)doHandle;

@end

@implementation DMHandler

- (void)handle
{
    BOOL bFlag = NO;
    bFlag = [self doHandle];
    if (self.successor && bFlag == NO) {
        [self.successor handle];
    }
    
}

// 子类需要重写
- (BOOL)doHandle
{
    BOOL bFlag = NO;
    
    return bFlag;
}

@end

@interface DMHandlerA : DMHandler

@end

@implementation DMHandlerA

- (BOOL)doHandle
{
    BOOL bFlag = NO;
    NSLog(@"%@:%@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    // 处理...

    return bFlag;
}

@end


@interface DMHandlerB : DMHandler

@end

@implementation DMHandlerB

- (BOOL)doHandle
{
    BOOL bFlag = NO;
    NSLog(@"%@:%@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    // 处理...

    return bFlag;
}

@end

@interface DMHandlerChain : NSObject

- (void)addHandler:(DMHandler *)handler;

- (void)handle;

@end

// DMHandlerChain 代码不变
@interface DMHandlerChain ()

@property (nonatomic, strong) DMHandler *head;

@property (nonatomic, strong) DMHandler *tail;

@end

@implementation DMHandlerChain

- (void)addHandler:(DMHandler *)handler
{
    if (self.head == nil) {
        self.head = handler;
        self.tail = handler;
    }
    
    self.tail.successor = handler;
}

- (void)handle
{
    [self.head handle];
}

@end

// 使用举例的代码也不变
- (void)testChain
{
    DMHandlerChain *handlerChain = [[DMHandlerChain alloc] init];
    DMHandlerA *handlerA = [[DMHandlerA alloc] init];
    [handlerChain addHandler:handlerA];
    
    DMHandlerB *handlerB = [[DMHandlerB alloc] init];
    [handlerChain addHandler:handlerB];
    
    [handlerChain handle];
}

职责链的第二种实现方式。DMHandlerChain类用数组而非链表来保存所有的处理器,并且需要在DMHandlerChain的- (void)handle方法中,以此调用每个处理器的- (BOOL)handle 方法。

@protocol DMHandlerDelegate <NSObject>

- (BOOL)handle;

@end

@interface DMHandlerA : DMHandler <DMHandlerDelegate>

@end

@implementation DMHandlerA

- (BOOL)handle
{
    BOOL bFlag = NO;
    
    NSLog(@"%@:%@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    // 处理...
    
    return bFlag;
}

@end

@interface DMHandlerB : DMHandler <DMHandlerDelegate>

@end

@implementation DMHandlerB

- (BOOL)handle
{
    BOOL bFlag = NO;
    NSLog(@"%@:%@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    // 处理...
    
    return bFlag;
}

@end

@interface DMHandlerChain : NSObject

- (void)addHandler:(id<DMHandlerDelegate>)handler;

- (void)handle;

@end

@interface DMHandlerChain : NSObject

- (void)addHandler:(id<DMHandlerDelegate>)handler;

- (void)handle;

@end

@interface DMHandlerChain ()

@property (nonatomic, strong) NSMutableArray<id<DMHandlerDelegate>> *handlers;

@end

@implementation DMHandlerChain

- (void)addHandler:(id<DMHandlerDelegate>)handler
{
    [self.handlers addObject:handler];
}

- (void)handle
{
    for (id<DMHandlerDelegate> handler in self.handlers) {
        BOOL bFlag = [handler handle];
        if (bFlag) {
            break;
        }
    }
}

- (NSMutableArray<id<DMHandlerDelegate>> *)handlers
{
    if (_handlers == nil) {
        _handlers = [[NSMutableArray<id<DMHandlerDelegate>> alloc] init];
    }
    
    return _handlers;
}

@end

职责链模式的应用场景

对于支持UGC(User Generated Content,用户生成内容)的应用来说,用户生成的内容可能包含一些敏感词(比如涉黄、广告、反动等词汇)。针对这个应用场景,就可以利用职责链模式来过滤这些敏感词。

@protocol DMSensitiveWordFilter <NSObject>

- (BOOL)doFilter:(NSString *)contentStr;

@end

@interface DMSexyWordFilter : NSObject <DMSensitiveWordFilter>

@end

@implementation DMSexyWordFilter

- (BOOL)doFilter:(NSString *)contentStr
{
    BOOL legal = YES;
    // ...
    
    return legal;
}

@end

@interface DMAdsWordFilter : NSObject <DMSensitiveWordFilter>

@end

@implementation DMAdsWordFilter

- (BOOL)doFilter:(NSString *)contentStr
{
    BOOL legal = YES;
    // ...
    
    return legal;
}

@end

@interface DMPoliticalWordFilter : NSObject <DMSensitiveWordFilter>

@end

@implementation DMPoliticalWordFilter

- (BOOL)doFilter:(NSString *)contentStr
{
    BOOL legal = YES;
    // ...
    
    return legal;
}

@end

@interface DMSensitiveWordFilterChain : NSObject

- (void)addFilter:(id<DMSensitiveWordFilter>)filter;

- (BOOL)filter:(NSString *)contentStr;

@end

@interface DMSensitiveWordFilterChain ()

@property (nonatomic, strong) NSMutableArray<id<DMSensitiveWordFilter>> *filters;

@end

@implementation DMSensitiveWordFilterChain

- (void)addFilter:(id<DMSensitiveWordFilter>)filter
{
    [self.filters addObject:filter];
}

- (BOOL)filter:(NSString *)contentStr
{
    BOOL legal = YES;
    for (id<DMSensitiveWordFilter> tmpFilter in self.filters) {
        if ([tmpFilter doFilter:contentStr] == NO) {
            legal = NO;
            break;
        }
    }
    
    return legal;
}

- (NSMutableArray<id<DMSensitiveWordFilter>> *)filters
{
    if (_filters == nil) {
        _filters = [[NSMutableArray<id<DMSensitiveWordFilter>> alloc] init];
    }
    
    return _filters;
}

@end

// 使用示例
- (void)testSensitiveWordFilter
{
    DMSensitiveWordFilterChain *filterChain = [[DMSensitiveWordFilterChain alloc] init];
    
    DMSexyWordFilter *sexyWordFilter = [[DMSexyWordFilter alloc] init];
    [filterChain addFilter:sexyWordFilter];
    
    DMPoliticalWordFilter *politicalWordFilter = [[DMPoliticalWordFilter alloc] init];
    [filterChain addFilter:politicalWordFilter];
    
    DMAdsWordFilter *adsWordFilter = [[DMAdsWordFilter alloc] init];
    [filterChain addFilter:adsWordFilter];
    
    BOOL leagl = [filterChain filter:@""];
    if (leagl) {
        // 发表
    } else {
        // 不发表
    }
}

职责链模式如何应对代码的复杂性

将大块代码逻辑拆分成函数,将大类拆分成小类,是应对代码复杂性的常用方法。应用职责链模式,把各个敏感词过滤函数拆分出来,设计成独立的类。

职责链模式如何让代码满足开闭原则,提高代码的扩展性

当要扩展新的过滤算法的时候,比如,还需要过滤特殊符号,职责链模式只需要添加一个DMSensitiveWordFilter类,并通过- (void)addFilter:(id<DMSensitiveWordFilter>)filter 方法将它添加到DMSensitiveWordFilterChain 中即可,其他代码完全不需要修改。
当添加新的过滤算法的时候,还是要修改客户端代码(使用示例代码),这样做也没有完全符合开闭原则。实际上,细化一下的话,可以把上面代码分成两类:框架代码和客户端代码。其中,使用示例代码属于客户端代码,也就是使用框架的代码。除使用示例代码外,其它的代码属于敏感词过滤框架代码。
假设敏感词过滤框架不是我们开发维护的,而是引入的一个第三方框架,如果要扩展一个新的过滤算法,不可能直接修改框架的源码。这个时候,利用职责链模式就能达到在不修改框架源码的情况下,基于职责链模式提供扩展点,来扩展新的功能。换句话说,在框架这个代码范围内实现了开闭原则。

相关文章

网友评论

      本文标题:iOS设计模式之职责链模式

      本文链接:https://www.haomeiwen.com/subject/hwmrcjtx.html