持续创造,加快成长!这是我参加「日新计划 10 月更文应战」的第1天,点击检查活动详情

1. 前语: 规划形式可以在大型项目中有哪些可落地的优化?

  • 笔者目前担任一个中大型iOS项目,用PPRows跑一下项目根文件,目前代码量约28W。
  • 在这样一个大型项目中,咱们组用了哪些办法对事务逻辑及代码架构进行解耦呢?
  • 在这种代码量级的项目中,有哪些接地气的,可落地的优化经验呢?
  • 在此抛砖引玉,欢迎大家一同彼此探讨。

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2. 落地

2.1 选用”单例形式”, 做一个更加单一职责的广告办理类.

2.1.1 单例形式导图

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.1.2 单例形式, 中心类文件构成

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.1.3 选用单例形式解耦, 中心代码文件解说

2.1.3.1 界说一个承继自NSObject的单例广告办理类ADManager

  • ADManager.h文件
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ADManager : NSObject
/// 供外部统一运用的单例类办法
+ (instancetype)sharedInstance;
@end
NS_ASSUME_NONNULL_END
  • ADManager.m文件
#import "ADManager.h"
@implementation ADManager
+ (instancetype)sharedInstance {
  // 静态局部变量
  static ADManager *adManager = nil;
  // 经过dispatch_once方式, 确保instance在多线程环境下只被创立一次
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    // 调用父类的办法创立实例, 防止跟重写本身的allocWithZone发生循环调用
    adManager = [[super allocWithZone:NULL] init];
  });
  return adManager;
}
// 重写本身的allocWithZone, 应对不运用sharedInstance办法直接经过alloc创立目标的状况
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
  return [self sharedInstance];
}
// MRC下重写copyWithZone, 应对经过copy复制目标的状况, OBJC_ARC_UNAVAILABLE
+ (id)copyWithZone:(struct _NSZone *)zone {
  return self;
}
@end

2.1.3.2 实践事务运用单例形式示例

//
// Viewontroller.m
// appDesignPattern
//
// Created by JackLee on 2022/9/21.
//
#import "ViewController.h"
#import "ADManager.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  // 测验单例形式
  [self testSingleADManager];
}
/// 测验单例形式
- (void)testSingleADManager {
  ADManager *adManager = [ADManager sharedInstance];
  ADManager *adManager2 = [ADManager new];
  NSLog(@"adManager === %@ ptr === %p", adManager, adManager);
  NSLog(@"adManager2 === %@ ptr === %p", adManager2, adManager2);
}

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.2 选用”指令形式”, 使行为参数化, 降低代码重合度

2.2.1 指令形式导图

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.2.2 指令形式, 中心类文件构成

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.2.3 指令形式对行为进行参数化处理以解耦, 中心代码文件解说

2.2.3.1 界说一个笼统指令类Command

  • Command.h文件
#import <Foundation/Foundation.h>
@class Command;
typedef void(^CommandCompletionCallBack)(Command *cmd);
@interface Command : NSObject
// 指令完结的回调
@property (nonatomic, copy) CommandCompletionCallBack completion;
/// 履行指令
- (void)execute;
/// 撤销指令
- (void)cancel;
/// 完结指令
- (void)done;
@end
  • Command.m文件
#import "Command.h"
#import "CommandManager.h"
@implementation Command
- (void)execute {
  // override to subclass, 交给子类复写详细完结
//  [self done];
}
- (void)cancel {
  self.completion = nil;
}
- (void)done {
  // 考虑到多线程的状况, 异步回到主队列
  dispatch_async(dispatch_get_main_queue(), ^{
    if (self.completion) {
      self.completion(self);
    }
   
    // 开释
    self.completion = nil;
    [[CommandManager sharedInstance].arrayCommands removeObject:self];
  });
}
@end
  • 详细的点赞指令LikedCommand.h
#import "Command.h"
NS_ASSUME_NONNULL_BEGIN
@interface LikedCommand : Command
@end
NS_ASSUME_NONNULL_END
  • 详细的点赞指令LikedCommand.m
#import "LikedCommand.h"
@implementation LikedCommand
- (void)execute {
  NSLog(@"履行点赞操作 ====");
  [self done];
}
@end
  • 详细的共享指令ShareCommand.h
#import "Command.h"
NS_ASSUME_NONNULL_BEGIN
@interface ShareCommand : Command
@end
NS_ASSUME_NONNULL_END
  • 详细的共享指令ShareCommand.m
#import "ShareCommand.h"
@implementation ShareCommand
- (void)execute {
  NSLog(@"履行共享操作 ====");
  [self done];
}
@end
  • 指令办理类CommandManager.h
#import <Foundation/Foundation.h>
#import "Command.h"
NS_ASSUME_NONNULL_BEGIN
@interface CommandManager : NSObject
/// 指令办理容器
@property(nonatomic, copy) NSMutableArray <Command *>*arrayCommands;
/// 指令办理者提供单例办法供运用者调用
+ (instancetype)sharedInstance;
/// 履行指令
+ (void)executeCommand:(Command *)cmd completion:(CommandCompletionCallBack)completion;
/// 撤销指令
+ (void)cancelCommand:(Command *)cmd;  
@end
NS_ASSUME_NONNULL_END
  • 指令办理类CommandManager.m
#import "CommandManager.h"
@implementation CommandManager
+ (instancetype)sharedInstance {
  static CommandManager *instance = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    instance = [[super allocWithZone:NULL] init];
  });
  return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
  return [self sharedInstance];
}
+ (void)executeCommand:(Command *)cmd completion:(CommandCompletionCallBack)completion {
  if (cmd) {
    // 假如指令正在履行不做处理, 否则添加并履行指令
    if (![self _isExecutingCommand:cmd]) {
      // 添加到指令容器傍边
      [[[self sharedInstance] arrayCommands] addObject:cmd];
     
      // 设置详细指令履行完结后的回调
      cmd.completion = completion;
     
      // 调用详细指令履行办法
      [cmd execute];
    }
  }
}
+ (void)cancelCommand:(Command *)cmd {
  if (cmd) {
    // 从指令容器傍边移除
    [[[self sharedInstance] arrayCommands] removeObject:cmd];
    // 撤销指令履行
    [cmd cancel];
  }
}
+ (BOOL)_isExecutingCommand:(Command *)cmd {
  if (cmd) {
    NSArray *cmds = [[self sharedInstance] arrayCommands];
 
    for (Command *aCmd in cmds) {
      // 当时指令正在履行
      if (cmd == aCmd) {
        return YES;
      }
    }
  }
  return NO;
} 
@end

2.2.3.2 实践事务运用指令形式示例

//
// Viewontroller.m
// appDesignPattern
//
// Created by JackLee on 2022/9/21.
//
#import "ViewController.h"
#import "LikedCommand.h"
#import "ShareCommand.h"
#import "CommandManager.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  // 测验指令形式
  [self testCommand];
}
/// 测验指令形式
- (void)testCommand {
  LikedCommand *liked = [LikedCommand new];
  ShareCommand *share = [ShareCommand new];
  [CommandManager executeCommand:liked completion:^(Command *cmd) {
    NSLog(@"点赞指令完结回调 cmd === %@", cmd);
  }];
  [CommandManager executeCommand:share completion:^(Command *cmd) {
    NSLog(@"共享指令完结回调 cmd === %@", cmd);
  }];
}
@end

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.3 选用”适配器”形式, 更优雅的为陈腐事务代码扩展新功能.

2.3.1 适配器形式导图

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.3.2 适配器形式解耦, 中心类文件构成

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.3.3 适配器形式解耦, 中心代码文件解说

2.3.3.1 界说一个承继自NSObject的适配器类AdapterTarget

  • AdapterTarget.h文件
#import "OldTarget.h"
NS_ASSUME_NONNULL_BEGIN
/// 适配目标
@interface AdapterTarget : NSObject
/// 被适配老事务目标
@property (nonatomic, strong) OldTarget *oldTarget;
/// 对原有办法进行适配器包装
- (void)adapertRequest;
@end
NS_ASSUME_NONNULL_END
  • AdapterTarget.m文件
//
// AdapterTarget.m
// appDesignPattern
//
// Created by JackLee on 2022/10/12.
//
#import "AdapterTarget.h"
@implementation AdapterTarget
- (OldTarget *)oldTarget {
  if (!_oldTarget) {
    _oldTarget = [[OldTarget alloc] init];
  }
  return _oldTarget;
}
- (void)adapertRequest {
  NSLog(@"新增额定处理A");
  [self.oldTarget oldOperation];
  NSLog(@"新增额定处理B");
}
@end
  • 久经考验的处理事务逻辑的旧类 OldTarget
  • OldTarget.h文件
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OldTarget : NSObject
/// 久经考验的旧处理办法
- (void)oldOperation;
@end
NS_ASSUME_NONNULL_END
  • OldTarget.m文件
#import "OldTarget.h"
@implementation OldTarget
- (void)oldOperation {
  NSLog(@"久经考验的旧处理办法");
}
@end

2.3.3.2 实践事务运用适配器形式示例

//
// ViewController.m
// appDesignPattern
//
// Created by JackLee on 2022/9/21.
//
#import "ViewController.h"
#import "AdapterTarget.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  // 测验适配器形式
  [self testAdapter];
}
- (void)testAdapter {
  AdapterTarget *adapterTarget = [AdapterTarget new];
  [adapterTarget adapertRequest];
}

2.4 选用”桥接形式”, 应对同一页面网络数据接口来回变动的场景, 进行逻辑解耦.

2.4.1 桥接形式导图

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.4.2 桥接形式解耦, 中心类文件构成

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.4.3 桥接形式解耦, 中心代码文件解说

2.4.3.1 界说一个笼统的基类BaseObjectA

  • BaseObjectA.h文件
#import <Foundation/Foundation.h>
#import "BaseObjectB.h"
NS_ASSUME_NONNULL_BEGIN
@interface BaseObjectA : NSObject
/// 桥接形式的中心完结
@property (nonatomic, strong) BaseObjectB *objB;
/// 获取数据
- (void)handle;
@end
NS_ASSUME_NONNULL_END
  • BaseObjectA.m文件
#import "BaseObjectA.h"
@implementation BaseObjectA
/**
A1 --> B1、B2 2种对应
A2 --> B1、B2 2种对应
*/
- (void)handle {
  // override to subclass 交给详细的子类复写
  [self.objB fetchData];
}
@end
  • 详细的页面A1 ObjectA1
  • ObjectA1.m文件
#import "ObjectA1.h"
@implementation ObjectA1
- (void)handle {
  // before 事务逻辑操作
  [super handle];
  // after 事务逻辑操作
}
@end
  • 不同接口的笼统父类BusinessB.h文件
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface BaseObjectB : NSObject
- (void)fetchData;
@end
NS_ASSUME_NONNULL_END
  • 不同接口的笼统父类BusinessB.m文件
#import "BaseObjectB.h"
@implementation BaseObjectB
- (void)fetchData {
  // override to subclass 交给子类完结
}
@end
  • 详细运用的接口B2的完结ObjectB.m文件
#import "ObjectB2.h"
@implementation ObjectB2
- (void)fetchData {
  // B2详细的逻辑处理
  NSLog(@"B2接口获取数据详细的逻辑处理 === ");
}
@end

2.4.3.2 实践事务运用桥接形式示例

//
// ViewController.m
// appDesignPattern
//
// Created by JackLee on 2022/9/21.
//
#import "ViewController.h"
#import "ObjectA1.h"
#import "ObjectA2.h"
#import "ObjectB1.h"
#import "ObjectB2.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  // 测验桥接形式
  [self testBridgeFetchData];
}
- (void)testBridgeFetchData {
  /**
  依据实践事务判断运用哪套详细数据
  A1 --> B1、B2 2种对应
  A2 --> B1、B2 2种对应
  */
  // 创立一个详细的ClassA
  BaseObjectA *objA = [ObjectA1 new];
//  BaseObjectA *objA = [ObjectA2 new];
  // 创立一个详细的ClassB
//  BaseObjectB *objB2 = [ObjectB1 new];
  BaseObjectB *objB2 = [ObjectB2 new];
  // 将一个详细的ClassB2 指定给笼统BaseClassB
  objA.objB = objB2;
  // A列表运用B2的接口获取数据
  [objA handle];
}

2.5 选用”职责链形式”, 应对产品大大提出的事务变更, 对事务代码进行解耦.

2.5.1 职责链形式导图

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.5.2 职责链形式解耦, 中心类文件构成

iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集

2.5.3 职责链形式解耦, 中心代码文件解说

2.5.3.1 界说一个笼统的基类BusinessObject

  • BusinessObject.h文件
#import <Foundation/Foundation.h>
//NS_ASSUME_NONNULL_BEGIN
@class BusinessObject;
/// 某一事务完结之后, 回来的成果是否有处理掉这个事务
typedef void(^CompletionBlock)(BOOL handled);
/// 这个事务对应的处理者, 有没有处理好这个事务
typedef void(^ResultBlock)(BusinessObject *handler, BOOL handled);
@interface BusinessObject : NSObject
/// 下一个呼应者(呼应链构成的要害)
@property (nonatomic, strong) BusinessObject *nextBusiness;
/// 呼应者的处理办法
- (void)handle:(ResultBlock)result;
/// 各个事务在该办法傍边做实践事务处理, 完结之后成果回来给调用方
- (void)handleBusiness:(CompletionBlock)completion;
@end
  • BusinessObject.m文件
#import "BusinessObject.h"
@implementation BusinessObject
/// 职责链进口办法
-(void)handle:(ResultBlock)result {
  CompletionBlock completion = ^(BOOL handled){
    // 当时事务处理掉了,上抛成果
    if (handled) {
      result(self, handled);
    }
    else {
      // 沿着职责链,指派给下一个事务处理
      if (self.nextBusiness) {
        [self.nextBusiness handle:result];
      }
      else {
        // 没有事务处理,上抛
        result(nil, NO);
      }
    }
  }; 
  // 当时事务进行处理
  [self handleBusiness:completion];
}
- (void)handleBusiness:(CompletionBlock)completion {
  /**
  事务逻辑处理
  例如异步网络恳求、异步本地照片查询等
  交给子类复写
  */
}
@end
  • 例如需要处理网络恳求的事务A BusinessA
  • 事务A的BusinessObject.h文件
#import "BusinessObject.h"
NS_ASSUME_NONNULL_BEGIN
@interface BusinessA : BusinessObject
@end
NS_ASSUME_NONNULL_END
  • 事务A的BusinessObject.m文件
#import "BusinessA.h"
@implementation BusinessA
- (void)handleBusiness:(CompletionBlock)completion {
  NSLog(@"处理事务A");
  // 事务次序: A -> B -> C
//  completion(NO);
  // 事务次序: C -> B -> A
  completion(YES);
}
@end
  • 事务B的BusinessObjectB.h文件
#import "BusinessObject.h"
NS_ASSUME_NONNULL_BEGIN
@interface BusinessB : BusinessObject
@end
NS_ASSUME_NONNULL_END
  • 事务B的BusinessObjectB.m文件
#import "BusinessB.h"
@implementation BusinessB
- (void)handleBusiness:(CompletionBlock)completion {
  NSLog(@"处理事务B");
  // 事务次序: A -> B -> C
//  completion(NO);
  // 事务次序: C -> B -> A
  completion(NO);
}
@end
  • 事务C的BusinessObjectC.h文件
#import "BusinessObject.h"
NS_ASSUME_NONNULL_BEGIN
@interface BusinessC : BusinessObject
@end
NS_ASSUME_NONNULL_END
  • 事务C的BusinessObjectC.m文件
#import "BusinessC.h"
@implementation BusinessC
- (void)handleBusiness:(CompletionBlock)completion {
  NSLog(@"处理事务C");
  // 事务次序: A -> B -> C
//  completion(YES);
  // 事务次序: C -> B -> A
  completion(NO);
}
@end

2.5.3.2 实践事务运用职责链形式办法

//
// ViewController.m
// appDesignPattern
//
// Created by JackLee on 2022/9/21.
//
#import "ViewController.h"
#import "BusinessA.h"
#import "BusinessB.h"
#import "BusinessC.h"
#import "appDesignPattern-Swift.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  [self testBusiness];
}
- (void)testBusiness {
  BusinessA *businessObjA = [BusinessA new];
  BusinessB *businessObjB = [BusinessB new];
  BusinessC *businessObjC = [BusinessC new];
  // 事务次序: A -> B -> C
//  businessObjA.nextBusiness = businessObjB;
//  businessObjB.nextBusiness = businessObjC;
  // 事务次序: C -> B -> A
  businessObjC.nextBusiness = businessObjB;
  businessObjB.nextBusiness = businessObjA;
  // 呼应者的处理办法, 职责链进口办法
  /*
  1. 当时事务处理掉了, 上抛成果
  2. 当时事务没处理掉, 沿着职责链, 指派给下一个事务处理, 假如没有事务处理, 继续上抛
  3. 对当时事务进行处理
  handler:
  handled: 事务处理成果
  */
  // 事务次序: A -> B -> C
//  [businessObjA handle:^(BusinessObject *handler, BOOL handled) {
//
//
//  }];
  // 事务次序: C -> B -> A
  [businessObjC handle:^(BusinessObject *handler, BOOL handled) {
    // handler: <BusinessA: 0x6000003da650>
    // handled: YES
  }]; 
}

发文不易, 喜欢点赞的人更有好运气 :), 定时更新+重视不迷路~

ps:欢迎参加笔者18年树立的研讨iOS审核及前沿技术的三千人扣群:662339934,坑位有限,补白“网友”可被群管经过~