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