先声明,这篇文章并非是讲什么是继承什么是工厂模式,而是根据我工作的实际场景和优化思路做的总结
在键盘上键入正确地咒语,屏幕会活动、变幻,显示出前所未有的也不可能存在的事物!
我先把所有版本文档罗列到这里:
iOS-继承-继承的工厂设计模式-多任务需求v1.1
iOS-继承-继承的工厂设计模式-多任务需求v1.2
iOS-协议-协议的工厂设计模式-多任务需求v1.3
我先直接介绍下v1.2版本的产品需求:
看图可知,对于版本v1.1中的需求,就新加了一个添加待办事项和删除待办事项的逻辑,首先我说下为什么我们会有这种奇葩的需求产生,我们做的App全部是以模块开发,每个模块都有各自功能,然后对接非常多的需求商,中间有实施者接入我们的模块,然后给需求商,也就是说,我这里模块可能有N多需求商的App在使用,这中间避免不了需求商的个性化需求,那么这个需求接口就是给他们自由添加删除事项。
一开始在做这个需求的时候,我是完全在v1.1版本上面去做的添加,无非就是增加两个接口给外部,他们实施者可以添加事情进来,有添加就有删除,很简单的道理,添加的事项是在App打开的时候就给进来的,那么相当于每次App打开都会去添加这个事项,但是或许我只是需要这个事项在第一次登陆才出现,那么删除接口就有用了。至于实施者是需要什么时候删除,以及删除的规则都是由他自己去定,我只提供逻辑。
在v1.1版本中,大家还记得我是使用的三个数组分别存储各类数据,在这里给自己留坑了:
坑1. 当删除事项的时候,你会发现很麻烦,你需要依次找到各个数组下面的值,依次删除其中数据,
坑2. v1.1版本的所有业务处理都是写在我的YxxAppLoginWaitWorking.m中的,那么实施者每添加一个事项就需要在YxxAppLoginWaitWorking.m中写代码,这样就违背了模块化开发了。
对于这两个坑,在我们小组讨论后,优化方案是这样的:
1.将业务、网络请求事项、手动加入事项、删除事项全部分开处理
2.将三个数组取出,只用一个数组去做操作
具体看下面代码和注释:
- YxxAppLoginWaitWorking.h
#import
@interface YxxAppLoginWaitWorking : NSObject
//初始化
+ (YxxAppLoginWaitWorking *)initAppLoginWaitWorking;
//调用业务逻辑
- (void)showAppLoginWaitWorking;
//手动添加事项
- (void)manualAddWaitWorking:(NSDictionary *)addWorking;
//手动删除事项
- (void)deleteWaitWorking:(NSString *)eventId;
@end
- YxxAppLoginWaitWorking.m
@interface YxxAppLoginWaitWorkingDataListModel : HFModel
@property (nonatomic, strong) NSArray *taskList; /**< 信息列表 */
@end
@implementation YxxAppLoginWaitWorkingDataListModel
@end
@interface YxxAppLoginWaitWorking ()
//相比v1.1版本这里只保存模型数组
@property (nonatomic, copy) NSMutableArray *waitWorkingModelAry; /**< 保存事件模型 */
@end
@implementation YxxAppLoginWaitWorking
/**
* 数组懒加载
*/
- (NSMutableArray *)waitWorkingModelAry
{
if (!_waitWorkingModelAry) {
_waitWorkingModelAry = [NSMutableArray array];
}
return _waitWorkingModelAry;
}
/**
* 单例初始化
*/
+ (YxxAppLoginWaitWorking *)initAppLoginWaitWorking
{
static YxxAppLoginWaitWorking *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[YxxAppLoginWaitWorking alloc] init];
});
return sharedInstance;
}
/**
* 开始事项
*/
- (void)showAppLoginWaitWorking
{
//监听登陆态
[RACObserve([YxxAppContext instance], isLogin) subscribeNext:^(id x) {
if ([x boolValue]){
//添加本地手势事项
NSDictionary *dict = @{@"eventId":@"事件5",@"eventPri":@"1011"};
//手动添加数据
[self manualAddWaitWorking:dict];
//网络请求数据
[self requestWaitWorking];
}
}];
}
/**
* 手动添加待办事项
*/
- (void)manualAddWaitWorking:(NSDictionary *)addWorking
{
YxxAppLoginWaitWorkingModel *loginWorkingModel=nil;
NSError *err;
//这里是手动加入的本地登陆事项
if (addWorking) {
if (addWorking[@"eventId"] || addWorking[@"eventPri"]) {
//去重操作,防止多次添加同一个事件
for (loginWorkingModel in self.waitWorkingModelAry) {
if ([loginWorkingModel.eventId isEqualToString:addWorking[@"eventId"]]) {
return;
}
}
loginWorkingModel = [MTLJSONAdapter modelOfClass:[YxxAppLoginWaitWorkingModel class] fromJSONDictionary:addWorking error:&err];
loginWorkingModel.waitWorkingType = waitWorkingManualAdd;
[self.waitWorkingModelAry addObject:loginWorkingModel];
}else{
LogError(@"取!手动加入的本地登陆事项,为空或者缺少字段");
}
}
}
/**
* 手动删除待办事项(这里删除只是排除在app没有退出的情况,用户重新登录,而会再次处理待办事项)
*/
- (void)deleteWaitWorking:(NSString *)eventId
{
NSMutableArray *copyAry = [NSMutableArray arrayWithArray:self.waitWorkingModelAry];
for (YxxAppLoginWaitWorkingModel *deleteModel in self.waitWorkingModelAry) {
if ([deleteModel.eventId isEqualToString:eventId]) {
[self.waitWorkingModelAry removeObject:copyAry];
}
}
[self.waitWorkingModelAry removeAllObjects];
[self.waitWorkingModelAry addObjectsFromArray:copyAry];
[copyAry removeAllObjects];
}
/**
* 网络请求
*/
- (void)requestWaitWorking
{
[request sendRequest:^(YxxRequestModel *requestModel, NSError *error) {
NSError *err;
YxxAppLoginWaitWorkingModel *waitWorkingModel=nil;
NSMutableArray *separationEvent = [NSMutableArray array];//存储待办事项接口下来的数据,以方便只删除此数据
if (error){
//接口失败了,也要处理其他端口获取的待办事项
if (self.waitWorkingModelAry.count) {
[self eventProcessing];
}
LogError(@"接口请求失败");
return;
}else{
id model = requestModel.dataModel;
if ([model isKindOfClass:[YxxAppLoginWaitWorkingDataListModel class]]) {
NSArray *taskList = ((YxxAppLoginWaitWorkingDataListModel *)model).taskList;
//判断有数据才存数组
if (taskList.count) {
for (NSDictionary *dict in taskList) {
waitWorkingModel = [MTLJSONAdapter modelOfClass:[YxxAppLoginWaitWorkingModel class] fromJSONDictionary:dict error:&err];
//过滤缺少字段的情况
if (waitWorkingModel.eventPri && waitWorkingModel.eventId && waitWorkingModel.eventStep) {
waitWorkingModel.waitWorkingType = waitWorkingRequest;
[self.waitWorkingModelAry addObject:waitWorkingModel];
}else{
LogError(@"后台数据缺少字段,待办事项不做处理,谢谢");
}
}
}
// 代办事项处理
[self eventProcessing];
}
}
}];
}
/**
* 待办事项的事件处理逻辑
*/
- (void)eventProcessing
{
//判空处理
if (self.waitWorkingModelAry.count == 0) {
return;
}
// 取优先级最高的,即eventPri最小的
YxxAppLoginWaitWorkingModel *minNumModel = self.waitWorkingModelAry[0];
for (YxxAppLoginWaitWorkingModel *model in self.waitWorkingModelAry) {
if ([model.eventPri integerValue] < [minNumModel.eventPri integerValue]) {
minNumModel = model;
}
}
//所有事项的父辈
YxxDoWaitWorkingBaseClass *doWaitWorking = [YxxDoWaitWorkingBaseClass createClichClassWithEventId:minNumModel.eventId];
[doWaitWorking startEvent:minNumModel];
// 做完待办事项后,删除
// 服务器代办事项做完后,删除服务器拿到的代办事项
NSMutableArray *copyAry = [NSMutableArray arrayWithArray:self.waitWorkingModelAry];
for (YxxAppLoginWaitWorkingModel *deleteModel in self.waitWorkingModelAry) {
if (deleteModel.waitWorkingType == waitWorkingRequest || deleteModel.waitWorkingType == waitWorkingAccessLogin) {
[copyAry removeObject:deleteModel];
}
}
[self.waitWorkingModelAry removeAllObjects];
[self.waitWorkingModelAry addObjectsFromArray:copyAry];
[copyAry removeAllObjects];
}
@end
- YxxDoWaitWorkingBaseClass.h
@interface YxxDoWaitWorkingBaseClass : NSObject
/**
* 在编译的过程中,子类的load方法调用,主要是得到一个字典存入数组中
*/
void registerWaitEvent(Class eventClass, NSString *eventPri);
/**
* 得到一个子类的类名
*/
NSString *classsNameStringWithEventId(NSString *eventPri);
/**
* 初始化
* eventId : 将优先级最高的id传入
*/
+(instancetype)createClichClassWithEventId:(NSString *)eventPri;
/**
* 类方法,子类在编译的时候会存入事件的id
*/
+(NSString *)eventId;
/**
* 事件需要做得事情
*/
-(void)startEvent:(YxxAppLoginWaitWorkingModel *)model;
/**
* 清除待办事项请求
*/
- (void)cancelWaitWorkingRequest:(NSString *)eventId;
@end
- YxxDoWaitWorkingBaseClass.m
#import "YxxDoWaitWorkingBaseClass.h"
#import "YxxRequest.h"
static NSMutableArray *eventIdAry;
/**
* 在编译的过程中,子类的load方法调用,主要是得到一个字典存入数组中
*/
NSString *classsNameStringWithEventId(NSString *eventId){
if (eventIdAry.count) {
for (NSDictionary *dict in eventIdAry) {
NSArray *eventIdKeyAry = [dict allKeys];
if ([eventIdKeyAry[0] isEqualToString:eventId]) {
return dict[eventIdKeyAry[0]];
}
}
}else{
return nil;
}
}
@implementation YxxDoWaitWorkingBaseClass
//根据出入的优先级找到对应事项,然后返回对应事项子类
+(instancetype)createClichClassWithEventId:(NSString *)eventPri
{
NSString *className = classsNameStringWithEventId(eventPri);
if (className) {
return [[NSClassFromString(className) alloc] init];
}
return nil;
}
void registerWaitEvent(Class eventClass, NSString *eventId){
if (eventId == nil) {
return;
}
if (eventIdAry == nil) {
eventIdAry = [NSMutableArray array];
}
[eventIdAry addObject:@{eventId:NSStringFromClass(eventClass)}];
}
+(NSString*)eventId
{
return nil;//事件优先级
}
-(void)startEvent:(YxxAppLoginWaitWorkingModel *)model
{
NSLog(@"%@",model);
}
/**
* 清除待办事项请求
*/
- (void)cancelWaitWorkingRequest:(NSString *)eventId
{
NSLog(@"%@",和服务器沟通清除事项);
}
@end
对于子类需要实现四个接口
- YxxEventOne.h
@interface YxxTestWaitWorking : YxxDoWaitWorkingBaseClass
@end
- YxxEventOne.m
#import "YxxEventOne.m"
@implementation YxxTestWaitWorking
+ (void)load
{
registerWaitEvent(self, [self eventId]);
}
+ (NSString *)eventId
{
return @"eventOne";
}
- (void)startEvent:(YxxAppLoginWaitWorkingModel *)model
{
NSLog(@"%@",写你需要做的事情,事件1);
}
@end
- YxxEventTwo.h
@interface YxxTestWaitWorking : YxxDoWaitWorkingBaseClass
@end
- YxxEventTwo.m
#import "YxxEventTwo.m"
@implementation YxxTestWaitWorking
+ (void)load
{
registerWaitEvent(self, [self eventId]);
}
+ (NSString *)eventId
{
return @"eventTwo";
}
- (void)startEvent:(YxxAppLoginWaitWorkingModel *)model
{
NSLog(@"%@",写你需要做的事情,事件2);
}
@end
如果你看懂了上面的逻辑,那么就能够看出,这种方式可以无限扩张,业务的灵活性打打提升。对于我自己的模块我不用在乎实施者的具体业务,我只要求实施者的业务继承我的父类,按照父类实现规定接口即可!相比v1.1版本代码逻辑条理性有所提升,可扩展性大幅提升,我觉得对于代码的优化,无非就是用最简洁的代码,写出更好的逻辑。后面还有一次优化,比现在的v1.2还有清晰
iOS-协议-协议的工厂设计模式-多任务需求v1.3