iOS 大神之路开发技巧iOS开发

Decorate Pattern装饰者模式-- iOS继承与代理

2017-01-05  本文已影响167人  小胡子杰克

场景

写这篇文章的背景是在看casatwy的网络层架构代码时对子类继承和协议代理方法的实现产生了疑惑,进行了探索。

问题

问题情景:父类的方法列表中和协议中有同样的方法(代码如下),子类继承方法同时代理方也实现协议方法,那么当父类调用decoratePatternTest这个方法时具体的执行方是谁?子类同时是代理方和不是代理方分别有什么样的情况呢?


#import <Foundation/Foundation.h>
@protocol BaseDecorateDelegate <NSObject>
- (NSString *)decoratePatternTest;
@end
@interface BaseProtocolTest : NSObject
@property (nonatomic, weak) id<BaseDecorateDelegate> decorate;
- (NSString *)decoratePatternTest;
- (void)startTest;
@end

casatwy注释

在casatwy的代码中遇到上述问题的有BaseAPIManager拦截器代码部分,作者的注释如下:

/*
    拦截器的功能可以由子类通过继承实现,也可以由其它对象实现,两种做法可以共存
    当两种情况共存的时候,子类重载的方法一定要调用一下super
    然后它们的调用顺序是BaseManager会先调用子类重载的实现,再调用外部interceptor的实现
    
    notes:
        正常情况下,拦截器是通过代理的方式实现的,因此可以不需要以下这些代码
        但是为了将来拓展方便,如果在调用拦截器之前manager又希望自己能够先做一些事情,所以这些方法还是需要能够被继承重载的
        所有重载的方法,都要调用一下super,这样才能保证外部interceptor能够被调到
        这就是decorate pattern
 */
 

注释中提到:

分情况实现验证

  1. 子类继承父类方法 & 子类没有遵守父类协议 & 其他类遵守协议实现代理方法
  2. 子类继承父类方法 & 遵守父类协议

父类方法:


- (NSString *)decoratePatternTest {
    NSLog(@"执行父类decoratePatternTest");
    NSString *string = @"基类中实现decoratePatternTest";
    if (self != self.decorate && [self.decorate respondsToSelector:@selector(decoratePatternTest)]) {
       string = [self.decorate decoratePatternTest];
    }
    return string;
}

子类方法:


- (NSString *)decoratePatternTest {
    [super decoratePatternTest];
    NSLog(@"子类执行decoratePatternTest");
    return @"子类中实现decoratePatternTest";
}

非子类代理者方法:


- (NSString *)decoratePatternTest {
    NSLog(@"执行过代理方实现decoratePatternTest");
    return @"代理方实现decoratePatternTest";
}

测试结果:

父类 子类 Other 父类 子类 Other
遵守协议实现方法 - N Y - Y N
继承方法 - Y N - Y N
方法执行顺序 2 1 3 2 1 -

关键

其实问题的关键是在代理者的协议方法调用的时机。

代码中不用调用父类方法的情况

作者的代码BaseAPIManager中的reformerParams方法在父类实例方法和协议方法中存在,但是子类继承实现时并不需要调用父类的 reformerParams,原因是父类中作了如下处理:


- (instancetype)init
{
    self = [super init];
    if (self) {
        if ([self conformsToProtocol:@protocol(BaseProtocolDelegate)]) {
            self.child = (id <BaseProtocolDelegate>)self;
        } else {
            NSException *exception = [[NSException alloc] init];
            @throw exception;
        }

    }
    return self;
}

- (NSString *)reformerParams {
    NSLog(@"执行父类reformerTest");
    IMP childIMP = [self.child methodForSelector:@selector(reformerTest)];
    IMP selfIMP = [self methodForSelector:@selector(reformerTest)];
    
    if (childIMP == selfIMP) {
        return @"子类没有继承此方法";
    } else {
        // 如果child是继承得来的,那么这里就不会跑到,会直接跑子类中的IMP。
        // 如果child是另一个对象,就会跑到这里
        NSString *result = nil;
        result = [self.child reformerParams];
        if (result) {
            return result;
        } else {
            return @"default";
        }
    }
}

Decorate Pattern 装饰者模式

装饰者模式动态地将责任附件到对象上,若要扩展功能,装饰着提供了比继承更具有弹性的方案。

装饰者模式的设计原则:


可以随心为一个类扩展功能,但不允许对已经存在的代码进行修改。

装饰者模式的主要特点:

装饰者模式示意图:

实际的例子:java中常用的java.io类就存在着大量装饰者

以上内容摘自《Head First设计模式》 第三章 装饰者模式 (79-107)

对应到iOS中本文的场景:

被装饰者 功能组件 装饰者
委托方父类 代理方OtherObject(非子类) 子类

其实在思考装饰者模式对应情况上,有点疑惑: 装饰者类Decorator没有找到对应的类

但装饰者模式中的关键点:

装饰者可以在被所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定目标。

在本文的例子中有明显体现:子类继承的方法中调用super方法,在这之前或者之后可以加上自己的行为,达到特定目标。

对装饰者模式的理解还比较基础有待继续研究……欢迎指正指导,谢谢!


iOS装饰模式的继续研究请看我的新文章Objective-C中的装饰模式
小胡子博客:冷读空间

上一篇下一篇

猜你喜欢

热点阅读