1. 程式人生 > >責任鏈模式在 iOS 中的應用

責任鏈模式在 iOS 中的應用

名稱

責任鏈模式 Chain of Responsibility Pattren

用途

  • 解耦訊息的傳送者和接受者。
  • 讓多個物件有機會處理某個請求(UI 響應鏈、Planck 中介軟體、流式業務流程(OA)、過濾器)。

實現

  • 為某個請求建立一個物件鏈,每個物件依次檢查次請求並對其進行處理,或者將它傳遞給鏈中的下一個物件。
  • 鏈的實現:使用現成的鏈(如繼承關係)或自己實現新鏈(next指標)
  • 鏈上的每個物件都採用同樣的介面處理或上拋事件

優點

  • 解耦請求的傳送者和接收者
  • 簡化物件(不關心鏈結構)
  • 鏈內成員可以靈活增刪調序

缺點

  • 不保證請求一定被處理
  • 靈活的長鏈可能給 Debug 增加複雜度

Cocoa 中的應用

  • Responder Chain 使得互動事件可以通過連結串列依次傳遞來被處理(或忽略)訊息。
  • 與使用者互動的物件(如Application, Window, View, ViewController)都是 NSResponder/UIResponder 的子類。
  • 首先確定 first responder (觸控事件採用 Hit-Test),隨後 responder 決定是否處理事件或通過 nextResponder 繼續傳遞。
  • 這個響應鏈大部分情況下是 View 的繼承鏈,Root UIView 的 next responder 是 UIViewController,VC 的下一個是 UIWindow,最後是 UIApplocation 的 delegate 且為 UIResponder 的子類;當然也可以通過 setNextResponder: 來改變它。

image

自己動手實現(Objective-C Code)

1. Array 在外部維護鏈

YFHandler

@interface YFHandler : NSObject

@property (assign, nonatomic, readwrite) NSUInteger index;

- (BOOL)handleBusiness:(NSUInteger)index;

@end

@implementation YFHandler

- (BOOL)handleBusiness:(NSUInteger)businessIndex {
    if (self.index
== businessIndex) { // Business Logic Here NSLog(@"business %@ has been handled with handler %@", @(businessIndex), @(self.index)); return YES; } else { return NO; } } @end

YFHandlerManager


@class YFHandler;

@interface YFHandlerManager : NSObject

- (void)addHandlerCount:(NSUInteger)count;
- (void)handleBusiness:(NSUInteger)businessIndex;

@end

@interface YFHandlerManager ()

@property (nonatomic, strong, readwrite) NSMutableArray<YFHandler *> *handlers;

@end

@implementation YFHandlerManager

- (instancetype)init {
    self = [super init];
    if (self) {
        self.handlers = [NSMutableArray array];
    }
    return self;
}

- (void)addHandlerCount:(NSUInteger)count {
    for (NSUInteger i = 1; i <= count; i++) {
        YFHandler *handler = [[YFHandler alloc] init];
        handler.index = i;
        [self.handlers addObject:handler];
    }
}

- (void)handleBusiness:(NSUInteger)businessIndex {
    [self.handlers enumerateObjectsUsingBlock:^(YFHandler * _Nonnull handler, NSUInteger idx, BOOL * _Nonnull stop) {

        BOOL handled = [handler handleBusiness:businessIndex];
        *stop = handled;

        BOOL isLastHandler = (idx == self.handlers.count - 1);
        if (isLastHandler && !handled) {
            NSLog(@"No handler is capable of handling businsess %@", @(businessIndex));
        }
    }];
}

Usage

- (void)handleBusinessOnArrayChain {
    YFHandlerManager *manager = [[YFHandlerManager alloc] init];
    [manager addHandlerCount:10];
    [manager handleBusiness:11];
}

2. Handler 自身維護鏈

YFHandlerWithNextPoint

@interface YFHandlerWithNextPoint : NSObject

@property (assign, nonatomic, readwrite) NSUInteger index;
@property (nonatomic, strong, readwrite) YFHandlerWithNextPoint *nextHander;

- (void)handleBusiness:(NSUInteger)index;

@end


@implementation YFHandlerWithNextPoint

- (void)handleBusiness:(NSUInteger)businessIndex {
    if (self.index == businessIndex) {
        // Business Logic Here
        NSLog(@"business %@ has been handled with handler %@", @(businessIndex), @(self.index));
    } else {
        [self.nextHander handleBusiness:businessIndex];
    }
}

@end

Usage

- (void)handleBusinessOnOwnChain {
    YFHandlerWithNextPoint *firstHandler = [self firstHandlerWithTotalCount:10];
    [firstHandler handleBusiness:8];
}

- (YFHandlerWithNextPoint *)firstHandlerWithTotalCount:(NSUInteger)handlerCount {

    YFHandlerWithNextPoint *firstHandler = nil;
    YFHandlerWithNextPoint *lastHandler = nil;

    for (NSUInteger i = 1; i <= handlerCount; i++) {
        YFHandlerWithNextPoint *thisHandler = [[YFHandlerWithNextPoint alloc] init];
        thisHandler.index = i;
        if (i == 1) {
            firstHandler = thisHandler;
        } else {
            lastHandler.nextHander = thisHandler;
        }
        lastHandler = thisHandler;
    }
    return firstHandler;
}