天天看点

iOS开发-APP组件模块化的理解模块化的意义组件化方案

文章目录

  • 模块化的意义
    • 模块化的粒度
    • 组件
  • 组件化方案
    • MGJRouter 的路由映射
    • CTMediator 中间者
      • Category的编写

模块化的意义

当项目大到一定程度,开发人员也多,所有的代码都集中到一个仓库,提交修改都要等其他人提交完成不报错才能开始,非常麻烦。

再者就是代码之间耦合严重,到处引用,穿插错综复杂,往往改变一个变量,需要修改很多处代码,很容易出错。

对于这种情况,就要进行架构整治,模块化无疑是一个好的方案。

模块化的粒度

对于模块化,并不是一味的全部分离成模块就是最好的。模块之间或许会有必要的引用以及上下级依赖关系,没必要完全的独立。再者需要考虑到业务变化时,可能又要重新划分模块,工作量和成本又高了。

iOS 模块化的划分应该遵循 SOLID原则 ,如下几点:

  • (S)单一原则

    :对象的功能要单一,不要是很多功能的集合体

例如

CALayer

负责动画视图显示,

UIView

则负责事件传递,事件响应

  • (O)开闭原则

    :“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;开闭原则中“闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代码。
  • (L)里氏替换原则

    :子类对象是可以替换基类对象的。所有引用基类的地方必须能透明地使用其子类的对象。

例如

KVO

的实现机制,利用

isa-swizzling

父类指向子类。

  • (I)接口隔离原则

    :接口的用途要单一,不要一个接口上根据入参不同实现不同的功能。

可以使用多个专门的协议,而不是使用一个庞大臃肿的协议。

  • (D)依赖反转原则

    :方法应该依赖抽象,不要依赖实例。面向接口编程,不要面向实现编程。让调用接口感觉不到内部是如何操作。

还一个

(D)迪米特法则

:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。即高聚合,低耦合。

可以顺带记忆

组件

可组装,独立的业务单元,高内聚,低耦合的特性。

iOS开发的组件,不应是

UI控件

,也不是

UIViewController

这种大UI和功能的集合,应该是包含

UI控件

,小功能集合的组件这样划分。

组件化方案

MGJRouter 的路由映射

https://github.com/meili/MGJRouter

蘑菇街的组件化方案

MGJRouter

[MGJRouter registerURLPattern:@"mgj://detail?id=:id" toHandler:^(NSDictionary *routerParameters) {
    NSNumber *id = routerParameters[@"id"];
    // create view controller with id
    // push view controller
}];
           

是一个路由方案

url-block

,通过注册

url

block

到一个单例中的

字典routes

中。

当调用

就通过

Url

去从

字典routes

取其

block

来执行。这样内存中维护了很多映射关系,

Url

这样的使用方式,也比较繁琐。而且需要将

Url

的时机必须要在调用之前,在

+load

进行注册又拖长了App启动时间,在其他时机注册又需要统筹兼顾。

另外还有

protocol-class

url-controller

,这些方式都大同小异,需要维护一个映射表,是一个短板,个人更倾向于

CTMediator

这种中间者架构

CTMediator 中间者

https://github.com/casatwy/CTMediator

其实就是使用

runtime

通过

[target performSelector:action withObject:params];

取到需要的数据,例如界面,视图。

如何使用这些界面视图就不关

CTMediator

的事了,这些界面,视图就可以封装成单独的模块,互无关系。

Category的编写

CTMediator

的关键在于其分类的编写,每个模块功能的分类由其模块开发者编写。

- (UIViewController *)CTMediator_viewControllerForDetail
{
    UIViewController *viewController = [self performTarget:kCTMediatorTargetA
                                                    action:kCTMediatorActionNativeFetchDetailViewController
                                                    params:@{@"key":@"value"}
                                         shouldCacheTarget:NO
                                        ];
    if ([viewController isKindOfClass:[UIViewController class]]) {
        // view controller 交付出去之后,可以由外界选择是push还是present
        return viewController;
    } else {
        // 这里处理异常场景,具体如何处理取决于产品
        return [[UIViewController alloc] init];
    }
}
           

这是

demo

中分类的一个方法实现,

kCTMediatorTargetA

隶属于

模块A

kCTMediatorTargetA

中有一个

kCTMediatorActionNativeFetchDetailViewController

方法可以获取一个

UIViewController`,

通过写

CTMediator

对于模块A的分类,就可以获取模块A中相关的界面以及UI,例如

CTMediator_viewControllerForDetail

iOS开发-APP组件模块化的理解模块化的意义组件化方案

这样的优势在于,没有了

key-value

的映射关系,不需要维护

url映射表

,更不需要存储block块,

Category For A

由开发

模块A

的人员来写,他很熟悉

模块A

(对于他来说将

模块A

中某个界面取出,并设置相关参数是很简单的事情),通过分类再转给不熟悉的人(无需关心

模块A

的内容)使用,就很方便了。

对于远程

url

调用,同样是通过将

url

解析成对应的动作,例如取某个视图,推出某个界面。

组件化能让工程架构更加清晰,每个人负责一个模块,通过pod导入,互不影响。