iOS 设计模式的应用 ⑮ 责任链
前言
如果将很多人的智慧连接成一个链条,每个人都有自己的专长,联合起来就能形成强大的实体,这很像团队成员之间的合作。智慧链条中的每个单元都可以为问题的解决作出贡献。如果一个人不知道如何解决问题,他就会把问题沿着链条向下传,有的时候,即使有人知道如何解决,依旧会把问题传递下去,这样就能完成解决问题的特定过程。
这种概念对于面向对象的软件设计同样适用,称为责任链模式。比如,让一组对象处理特定的请求,而对这个组添加或删除处理程序都不应影响组的完成性。
什么是责任链模式
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链,其避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
![](https://img.haomeiwen.com/i2438680/666b8404cdb77c1d.png)
Handler
是上传抽象类,定义了一个方法 handlerRequest
,处理它知道如何处理的请求对象。ConcreteHandler1
和 ConcreteHandler2
实现了 handlerRequest
来处理它们认识的请求对象。 Handler
也有一个指向另一个同类实例 successor
的引用。当调用 Handler
实例的 handlerRequest
消息不知道如何处理请求时,会用同样的消息发送给 successor
。
什么时候使用责任链模式
- 有多个对象可以处理请求,而处理程序只有在运行时才能确定;
- 向一组对象发出请求,而不想显式指定请求的特定处理程序;
责任链模式的优缺点
责任链模式的优点
- 降低耦合度。它将请求的发送者和接收者解耦。
- 简化了对象。使得对象不需要知道链的结构。
- 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
- 增加新的请求处理类很方便。
责任链模式的缺点
- 不能保证请求一定被接收。
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
- 可能不容易观察运行时的特征,有碍于除错。
责任链模式的实现
创建抽象类 AbstractLogger,带有详细的日志记录级别。
typedef enum : NSUInteger {
Info,
Debug,
Error,
} LogLevel;
@interface AbstractLogger : NSObject
- (instancetype)initWithLevel:(LogLevel)level;
@property (nonatomic, assign) LogLevel level;
@property (nonatomic, strong) AbstractLogger *nextLogger;
- (void)logMessage:(NSString *)message Level:(LogLevel)level;
- (void)write:(NSString *)message;
@end
@implementation AbstractLogger
- (instancetype)initWithLevel:(LogLevel)level{
self = [super init];
if (self) {
self.level = level;
}
return self;
}
- (void)logMessage:(NSString *)message Level:(LogLevel)level{
if (level == self.level) {
[self write:message];
}
if (self.nextLogger) {
[self.nextLogger logMessage:message Level:level];
}
}
- (void)write:(NSString *)message{
}
@end
然后我们创建三种类型的记录器,都扩展了 AbstractLogger。每个记录器消息的级别是否属于自己的级别,如果是则相应地打印出来,否则将不打印并把消息传给下一个记录器。
@interface ConsoleLogger : AbstractLogger
@end
@implementation ConsoleLogger
- (void)write:(NSString *)message{
NSLog(@"Console Logger %@",message);
}
@end
@interface FileLogger : AbstractLogger
@end
@implementation FileLogger
- (void)write:(NSString *)message{
NSLog(@"File Logger %@",message);
}
@end
@interface ErrorLogger : AbstractLogger
@end
@implementation ErrorLogger
- (void)write:(NSString *)message{
NSLog(@"Error Logger %@",message);
}
@end
向响应链发送请求
- (void)logMessage{
AbstractLogger *loggerChain = [self getChainOfLoggers];
[loggerChain logMessage:@"information" Level:Info];
[loggerChain logMessage:@"debug" Level:Debug];
[loggerChain logMessage:@"error" Level:Error];
}
- (AbstractLogger *)getChainOfLoggers{
ErrorLogger *errorLogger = [[ErrorLogger alloc] initWithLevel:Error];
FileLogger *fileLogger = [[FileLogger alloc] initWithLevel:Debug];
ConsoleLogger *consoleLogger = [[ConsoleLogger alloc] initWithLevel:Info];
[errorLogger setNextLogger:fileLogger];
[fileLogger setNextLogger:consoleLogger];
return errorLogger;
}
Cocoa 中的责任链模式
应用程序框架包括一个称为响应者链的架构。该链由一系列响应者对象(继承自UIResponder
) 事件(例如,鼠标单击)或操作消息被传递并(通常)最终被处理。如果给定的响应者对象不处理特定消息,它会将消息传递给链中的下一个响应者。响应者对象在链中的顺序通常由视图层次结构决定,在层次结构中从较低级别到较高级别的响应者,如果视图由UIViewController
对象管理,则视图控制器将成为链中的下一个响应者(事件或操作消息从那里传递到视图的父视图)。响应者链上的事件和动作消息的路径是不同的。
总结
责任链模式其主要思想是对象引用了同一类型的另一个对象,形成一条链。链中的每个对象实现了同样的方法,处理对链中第一个对象发起的同一个请求。如果一个对象不知道如何处理,就把请求传给下一个响应器。