前言
文章的标题有点绕口,不过想了半天,想不到更好的标题了。本文的诞生有一部分功劳要归于iOS应用现状分析,标题也是来源于原文中的“能把代码职责均衡的划分到不同的功能类里”。如果你看过我的文章,就会发现我是一个MVC
主导开发的人。这是因为开发的项目总是算不上大项目,在合理的代码职责分工后项目能保持良好的状态,就没有使用到其他架构开发过项目(如果你的状态跟笔者差不多,就算不适用其他架构模式,你也应该自己学习)
OK,简短来说,在很早之前我就有写这么一篇文章的想法,大致是在当初面试很多iOS开发者的时候这样的对话萌生的念头,下面的对话是经过笔者总结的,切勿对号入座:
Q: 你在项目中使用了MVVM的架构结构,能说说为什么采用的是这种结构吗?
A: 这是因为我们的项目在开发中控制器的代码越来越多,超过了一千行,然后觉得这样控制器的职责太多,就采用一个个ViewModel把这些职责分离出来
Q: 能说说你们控制器的职责吗?或者有源码可以参考一下吗?
面试者拿出电脑展示源码
最后的结果就是,笔者不认为面试者需要使用到MVVM
来改进他们的架构,这里当然是见仁见智了。由于对方代码职责的不合理分工导致了View
和Model
层几乎没有业务逻辑,从而导致了控制器的失衡,变得笨重。在这种情况下即便他使用了ViewModel
将控制器的代码分离了出来,充其量只是将垃圾挪到另一个地方罢了
。我在MVC架构杂谈中提到过自身对MVC
三个模块的职责认识,当你想将MVC
改进成MVX
的其他结构时,应当先思考自己的代码职责是不是已经均衡了。
码农小明的项目
在开始之前,还是强烈推荐推荐《重构-改善既有代码的设计》
这本书,一本好书或者好文章应该让你每次观赏时都能产生不同的感觉。
正常来说,造成你代码笨重的最大凶手是重复的代码,例如曾经笔者看过这样一张界面图以及逻辑代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
@interface XXXViewController @property (weak, nonatomic) IBOutlet UIButton * rule1; @property (weak, nonatomic) IBOutlet UIButton * rule2; @property (weak, nonatomic) IBOutlet UIButton * rule3; @property (weak, nonatomic) IBOutlet UIButton * rule4; @end @implementation XXXViewController - (IBAction)actionToClickRule1: (id)sender { [_rule1 setSelected: YES]; [_rule2 setSelected: NO]; [_rule3 setSelected: NO]; [_rule4 setSelected: NO]; } - (IBAction)actionToClickRule2: (id)sender { [_rule1 setSelected: NO]; [_rule2 setSelected: YES]; [_rule3 setSelected: NO]; [_rule4 setSelected: NO]; } - (IBAction)actionToClickRule1: (id)sender { [_rule1 setSelected: NO]; [_rule2 setSelected: NO]; [_rule3 setSelected: YES]; [_rule4 setSelected: NO]; } - (IBAction)actionToClickRule1: (id)sender { [_rule1 setSelected: NO]; [_rule2 setSelected: NO]; [_rule3 setSelected: NO]; [_rule4 setSelected: YES]; } @end |
别急着嘲笑这样的代码,曾经的我们也写过类似的代码。这就是最直接粗浅的重复代码,所有的重复代码都和上面存在一样的毛病:亢长、无意义、占用了大量的空间。实际上,这些重复的代码总是分散在多个类当中,积少成多让我们的代码变得笨重。因此,在讨论你的项目是否需要改进架构之前,先弄清楚你是否需要消除这些垃圾。
举个例子,小明开发的一款面向B端的应用中允许商户添加优惠活动,包括开始日期和结束日期:
1 2 3 4 5 6 7 8 9 |
@interface Promotion: NSObject + (instancetype)currentPromotion; @property (readonly, nonatomic) CGFloat discount; @property (readonly, nonatomic) NSDate * start; @property (readonly, nonatomic) NSDate * end; @end |
由于商户同一时间只会存在一个优惠活动,小明把活动写成了单例,然后其他模块通过获取活动单例来计算折后价格:
1 2 3 4 5 |
// module A Promotion * promotion = [Promotion currentPromotion]; NSDate * now = [NSDate date]; CGFloat discountAmount = _order.amount; if ([now timeIntervalSinceDate: promotion.start] > 0 && [now timeIntervalSinceDate: promotion.end] 0 && [now timeIntervalSinceDate: promotion.end] |
MVC
主导开发的人。这是因为开发的项目总是算不上大项目,在合理的代码职责分工后项目能保持良好的状态,就没有使用到其他架构开发过项目(如果你的状态跟笔者差不多,就算不适用其他架构模式,你也应该自己学习)
OK,简短来说,在很早之前我就有写这么一篇文章的想法,大致是在当初面试很多iOS开发者的时候这样的对话萌生的念头,下面的对话是经过笔者总结的,切勿对号入座:
Q: 你在项目中使用了MVVM的架构结构,能说说为什么采用的是这种结构吗?
A: 这是因为我们的项目在开发中控制器的代码越来越多,超过了一千行,然后觉得这样控制器的职责太多,就采用一个个ViewModel把这些职责分离出来
Q: 能说说你们控制器的职责吗?或者有源码可以参考一下吗?
面试者拿出电脑展示源码
最后的结果就是,笔者不认为面试者需要使用到MVVM
来改进他们的架构,这里当然是见仁见智了。由于对方代码职责的不合理分工导致了View
和Model
层几乎没有业务逻辑,从而导致了控制器的失衡,变得笨重。在这种情况下即便他使用了ViewModel
将控制器的代码分离了出来,充其量只是将垃圾挪到另一个地方罢了
。我在MVC架构杂谈中提到过自身对MVC
三个模块的职责认识,当你想将MVC
改进成MVX
的其他结构时,应当先思考自己的代码职责是不是已经均衡了。
码农小明的项目
在开始之前,还是强烈推荐推荐《重构-改善既有代码的设计》
这本书,一本好书或者好文章应该让你每次观赏时都能产生不同的感觉。
正常来说,造成你代码笨重的最大凶手是重复的代码,例如曾经笔者看过这样一张界面图以及逻辑代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
@interface XXXViewController @property (weak, nonatomic) IBOutlet UIButton * rule1; @property (weak, nonatomic) IBOutlet UIButton * rule2; @property (weak, nonatomic) IBOutlet UIButton * rule3; @property (weak, nonatomic) IBOutlet UIButton * rule4; @end @implementation XXXViewController - (IBAction)actionToClickRule1: (id)sender { [_rule1 setSelected: YES]; [_rule2 setSelected: NO]; [_rule3 setSelected: NO]; [_rule4 setSelected: NO]; } - (IBAction)actionToClickRule2: (id)sender { [_rule1 setSelected: NO]; [_rule2 setSelected: YES]; [_rule3 setSelected: NO]; [_rule4 setSelected: NO]; } - (IBAction)actionToClickRule1: (id)sender { [_rule1 setSelected: NO]; [_rule2 setSelected: NO]; [_rule3 setSelected: YES]; [_rule4 setSelected: NO]; } - (IBAction)actionToClickRule1: (id)sender { [_rule1 setSelected: NO]; [_rule2 setSelected: NO]; [_rule3 setSelected: NO]; [_rule4 setSelected: YES]; } @end |
别急着嘲笑这样的代码,曾经的我们也写过类似的代码。这就是最直接粗浅的重复代码,所有的重复代码都和上面存在一样的毛病:亢长、无意义、占用了大量的空间。实际上,这些重复的代码总是分散在多个类当中,积少成多让我们的代码变得笨重。因此,在讨论你的项目是否需要改进架构之前,先弄清楚你是否需要消除这些垃圾。
举个例子,小明开发的一款面向B端的应用中允许商户添加优惠活动,包括开始日期和结束日期:
1 2 3 4 5 6 7 8 9 |
@interface Promotion: NSObject + (instancetype)currentPromotion; @property (readonly, nonatomic) CGFloat discount; @property (readonly, nonatomic) NSDate * start; @property (readonly, nonatomic) NSDate * end; @end |
由于商户同一时间只会存在一个优惠活动,小明把活动写成了单例,然后其他模块通过获取活动单例来计算折后价格:
1 2 3 4 5 |
// module A Promotion * promotion = [Promotion currentPromotion]; NSDate * now = [NSDate date]; CGFloat discountAmount = _order.amount; if ([now timeIntervalSinceDate: promotion. |