iOS设计原则之里氏替换原则

随笔9个月前发布 黄金卡
90 0 0

里氏替换原则

里氏替换原则的英文是Liskov Substitution Principle, 简写为LSP。英文描述为 Functions that use pointers of references to base classes must be able to use objects of derived classes without knowing it。翻译成中文就是:子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏。
如下代码,父类DMTransporter 使用NSURLSession类来传输网络数据。子类
DMSecurityTransporter 集成父类 DMTransporter,增加了额外的功能,支持传输appId和appToken安全认证信息。

@interface DMTransporter : NSObject

- (void)sendRequest:(NSMutableURLRequest *)request;

@end


#import "DMTransporter.h"

@implementation DMTransporter

- (void)sendRequest:(NSMutableURLRequest *)request {
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
    [dataTask resume];
}

@end


@interface DMSecurityTransporter : DMTransporter

@property (nonatomic, strong) NSString *appId;

@property (nonatomic, strong) NSString *appToken;

@end

#import "DMSecurityTransporter.h"

@implementation DMSecurityTransporter

- (void)sendRequest:(NSMutableURLRequest *)request {
    if (self.appId.length > 0 && self.appToken.length > 0) {
        [request setValue:self.appId forHTTPHeaderField:@"app-id"];
        [request setValue:self.appToken forHTTPHeaderField:@"app-token"];
    }
    
    [super sendRequest:request];
}

@end

子类DMSecurityTransporter 的设计完全符合里氏替换原则,可以替换父类出现的任何位置,并且原来代码的逻辑行为不变且正确性也没有被破坏。
下面对DMSecurityTransporter类中的sendRequest方法稍加改造一下。改造前,如果appId或者appToken没有设置,就不做校验;改造后,如果appId或者appToken没有设置,就直接抛出异常。

- (void)sendRequest:(NSMutableURLRequest *)request {
    if (self.appId == nil ||
        self.appId.length == 0 ||
        self.appToken == nil ||
        self.appToken.length == 0) {
        @throw [NSException exceptionWithName:@"DMNoAuthorizationException" reason:@"未授权异常" userInfo:nil];
        return;
    }
    [request setValue:self.appId forHTTPHeaderField:@"app-id"];
    [request setValue:self.appToken forHTTPHeaderField:@"app-token"];
    [super sendRequest:request];
}


- (void)demoFunction:(DMTransporter *)transporter {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@""]];
    [transporter sendRequest:request];
}

改造后,如果传递给demoFunction方法的是父类DMTransporter 对象,那么demoFunction方法不会抛出异常,但如果传递的是子类DMSecurityTransporter对象,那demoFunction方法就有可能抛出异常。子类替换父类传递给demoFunction方法之后,整个程序的逻辑行为有了改变。改造之后的DMSecurityTransporter类的设计是不符合里氏替换原则的。
里氏替换是一种设计原则,用来指导继承关系中子类该如何设计的,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑以及不破坏原有程序的正确性。

那些代码违背里氏替换原则

  • 1、子类违背父类声明要实现的功能
  • 2、子类违背父类对输入、输出、异常的约定
  • 3、子类违背父类注释中所罗列的任何特殊说明
© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...