贝聊的移动客户端分别有家长端和老师端,一家公司里同时维护多个业务上有关联性的app这种情况其实很常见,例如一些提供
O2O
服务的公司,经常会分用户端和商家端。这些客户端虽然各自负责着一个业务环里面的不同部分,看似不相关,但其实内在的设计、代码都有很多共同之处。
我们编写代码时一条最重要的军规是 DRY (Don't Repeat Yourself),意思就是同样或
者相似的代码只写一次,通过代码复用的技巧做成公用的组件。项目工期紧张时,其他的一些编码守则都可以稍微变通一下,但唯独
DRY 是绝对要遵守的。这样做最大的好处是当发生需求变更、重构或者修复 bug 时,只要改动一处的代码就可以了。如果采用到处 copy
代码的方式,则需要在每一处引用到的地方做修改,很容易就会出现遗漏。并且时间一长,这些复制的代码很容易会渐行渐远,衍生出许多不同的分支,维护难度呈指数级上升。稍有经验的程序员应该都知道到处拷代码就是挖坑的开始,本文以一个较简单的UI
组件为例,介绍贝聊 iOS 组在设计可复用组件时的一点小技巧。
贝聊的家长版和老师版针对的受众不同,设计语言、配色等方面也有点不同,以最简单的自定义提示框为例:
家长版:
老师版:
主要的不同点:
-
按钮的圆角半径 (cornerRadius)
-
按钮的大小、位置 (frame)
-
文字的字号 (fontSize)
-
文字内容到提示框边界的距离 (contentInsets)
-
其实之前连按钮的颜色都不一样,不过最近UI改版了
初看起来不同点很多,但仔细看其实只是一些设计上的元素有不同。事实上家长版和老师版的提示框其实底层用的都是同一套代码,这个弹框组件BLAlertController是我们
iOS 组一个新入行的小伙写的,很好地遵守了 DRY 原则,灵活性和代码质量都非常高。本文就用这个组件为例来说说,怎样在多个 app
之间优雅地复用代码。
先来看看初始化方法,alertController的命名是仿照系统的UIAlertController,但是因为 UI 是高度可定制的,所以多加入了很多参数。
+ (instancetype)alertControllerWithTitle:(NSString *)title
message:(NSString *)message
buttonTextColor:(UIColor *)textColor
buttonBackgroundColor:(UIColor *)buttonBackgroundColor
cornerRadius:(CGFloat)cornerRadius
.... // 篇幅原因,点击回调和其他配置项都省略,全部列出来的话超过二十项
这里遇到的第一个问题就是参数列表过长,Objective-C 没有默认参数也没有方法重载,如果每次初始化都要填写这一大堆参数,这样的组件也未免太难用了。
其实
iOS SDK
的代码里面就有很多优秀的设计模式的应用范例,遇到问题的时候参考一下,会有很多收获。这里遇到的问题主要是代码架构的问题,发散一下,发现
Foundation
框架的 NSURLSession也是有很多可配置的属性的。苹果的工程师把这些可选参数专门构造成了一个NSURLSessionConfiguration来管理这些可配置属性。创建一个NSURLSession时,需要传入一个NSURLSessionConfiguration来指定一些参数,而NSURLSessionConfiguration的大部分属性都是有默认值的,例如timeoutIntervalForRequest。通过NSURLSessionConfiguration.defaultSessionConfiguration方法可以创建一个默认的 configuration,此时timeoutIntervalForRequest的默认值是60,这个值能适用于大部分情况。如果有特殊的需求也可以自行调整。
我们在99%的情况下其实都只是想用默认样式的弹框,这时创建一个可定制的,带默认值的配置类就是很好的解决方法。
依葫芦画瓢,我们也创建一个BLAlertConfiguration,定义大致如下:
@interface
BLAlertConfiguration : NSObject
// 配置类实现了深拷贝@property
(nonatomic) UIColor *buttonTextColor;@property (nonatomic) UIColor
*buttonBackgroundColor;@property (nonatomic) CGFloat cornerRadius;//
默认的配置项@property (class, nonatomic) BLAlertConfiguration
*defaultConfiguration;
... //其他可配置项由于篇幅原因不一一列举了@end@interface BLAlertController : UIViewController- (instancetype)initWithTitle:(NSString *)title
message:(NSString *)message
configuration:(BLAlertConfiguration *)configuration;
- (instancetype)initWithTitle:(NSString *)title
message:(NSString *)message;@end