如果要做成离散型的API调用,那么使用继承是逃不掉的。BaseAPIManager里面负责集约化的部分,外部派生的XXXAPIManager负责离散的部分,对于BaseAPIManager来说,离散的部分有一些是必要的,比如API名字等,而我们派生的目的,也是为了提供这些数据。
我在这篇文章里面列举了种种继承的坏处,呼吁大家尽量不要使用继承。但是现在到了不得不用继承的时候,所以我得提醒一下大家别把继承用坏了。
在APIManager的情况下,我们最直觉的思路是BaseAPIManager提供一些空方法来给子类做重载,比如apiMethodName这样的函数,然而我的建议是,不要这么做。我们可以用IOP的方式来限制派生类的重载。
大概就是长这样:
BaseAPIManager的init方法里这么写:
// 注意是weak。
@property (nonatomic, weak) id<APIManager> child;
- (instancetype)init {
self = [super init];
if ([self conformsToProtocol:@protocol(APIManager)]) {
self.child = (id<APIManager>)self;
} else {
// 不遵守这个protocol的就让他crash,防止派生类乱来。
NSAssert(NO, "子类必须要实现APIManager这个protocol。");
}
return self;
}
protocol这么写,把原本要重载的函数都定义在这个protocol里面,就不用在父类里面写空方法了:
@protocol APIManager <NSObject>
@required
- (NSString *)apiMethodName;
...
@end
然后在父类里面如果要使用的话,就这么写:
[self requestWithAPIName:[self.child apiMethodName] ......];
简单说就是在init的时候检查自己是否符合预先设计的子类的protocol,这就要求所有子类必须遵守这个protocol,所有针对父类的重载、覆盖也都以这个protocol为准,protocol以外的方法不允许重载、覆盖。
而在父类的代码里,可以不必遵守这个protocol,保持了未来维护的灵活性。
这么做的好处就是避免了父类写空方法,同时也给子类带上了紧箍咒:要想当我的孩子,就要遵守这些规矩,不能乱来。业务方在实现子类的时候,就可以根据protocol中的方法去一一实现,然后约定就比较好做了:不允许重载父类方法,只允许选择实现或不实现protocol中的方法。
关于这个的具体的论述在这篇文章里面有,感兴趣的话可以看看。
网络层与业务层对接部分的小总结
这一节主要是讲了以下这些点:
- 使用delegate来做数据对接,仅在必要时采用Notification来做跨层访问
- 交付NSDictionary给业务层,使用Const字符串作为Key来保持可读性
- 提供reformer机制来处理网络层反馈的数据,这个机制很重要,好处极多
- 网络层上部分使用离散型设计,下部分使用集约型设计
- 设计合理的继承机制,让派生出来的APIManager受到限制,避免混乱
应该不止这5点...
读完之后,感觉受益良多,打算把公司的项目网络层按照casa大神的网络设计方案给重构一下。