如何迁移至 Coordinator 模式

1,162 阅读2分钟

关于 Coordinator 模式已经在这篇文章介绍过,里面也把相关的英文文章列了出来。Coordinator 模式更适合从一开始就架构好,对于老项目这里提出一种个人认为相对还不错的迁移方案以供参考。

如何迁移

大部分情况下,我们都是直接在一个AVC的 .m 里面导入另一个BVC的 .h 文件,然后在 A 的某个跳转方法里构造 B 出来,直接 push 或 present。

// AVC.m
import "BVC.h"

- (void)onClickPushB{
BVC *b = [BVC new];
[self.navigationController pushVC:b];
}

造成耦合的原因是因为在 A 里面直接构造了 B,因此我们首先还是得把这个逻辑通过委托模式给弄出去。

// AVC.h
@protocol ACoordinatorDelegate 
-(void)AvcOnClickPushB:(UIViewController *)vc;
@end

@property (weak) id<ACoordinatorDelegate> delegate;

原来的调用改成这样,同时也不需要再导入 BVC.h 了:

- (void)onClickPushB{
[self.delegate AvcOnClickPushB:self];
}

现在我们需要在构造 A 的地方给 A 的delegate赋值,因为我想要改动尽可能小(不改动原来的跳转逻辑),所以 A 的delegate还是A自身。

// tabbarController.m

AVC *a = [AVC new];
a.delegate = a;

新建 A 的 category 文件,实现ACoordinatorDelegate协议。

@implementation AVC (ACoordinatorDelegateIMP)
- (void)AvcOnClickPushB:(UIViewController *)vc{
BVC *b = [BVC new];
b.delegate = b;
[self.navigationController pushVC:b];
}
@end

相比原来的实现,最多多一句代码(如果 BVC 也需要跳转的话)。而此时 AVC 已经消除了控制器之间的耦合,提高了可扩展性可复用性。

对于直接耦合的传统改进做法是设计一个新类Router,把所有跳转方法集中到这个类里面,然后所有的跳转都调用Router的方法。做完了上面这些后,一样可以用Router,让Router遵循这些协议,把这些 category 里的方法统统搬到Router对应的 category 里面,把self改成vc即可。

@implementation Router 
#pragma mark - ACoordinatorDelegate
- (void)AvcOnClickPushB:(UIViewController *)vc{
BVC *b = [BVC new];
b.delegate = self;
[vc.navigationController pushVC:b];
}
@end

如果从已经有Router或者CTMediator的情况迁移的话,也是一样的步骤。

迁移到 Coordinator 模式的时候,也只需要新增相应的 Coordinator 类,把这些方法搬到对应的 .m 里,把delegate赋值为self

@implementation ACoordinator 

- (void)start{
AVC *a = [AVC new];
a.delegate = self;
[self.rootVC pushViewController:a animated:NO];
}

#pragma mark - ACoordinatorDelegate
- (void)AvcOnClickPushB:(UIViewController *)vc{
BVC *b = [BVC new];
b.delegate = self;
[self.rootVC pushViewController:b animated:NO];
}
@end

当然还有个全局的AppCoordinator不能忘了,一般由AppDelegate持有作为启动入口。

总结

这种迁移方案是比较符合开闭原则的,无论最后是用RouterCTMediator,又或者Coordinator,都是新增了一个间接层,只换了实现,对原有代码的修改都相对少,修改控制器的delegate依赖使用不同的实现,三者共存也没问题。而且就算不用中介者间接层,只是像上面分离出 category,也能使代码清晰不少了。

最后,Github 上关于 Coordinator 模式基本都是 Swift 实现,这里有一个OC实现以供参考。