文章目錄
- 子產品化的意義
-
- 子產品化的粒度
- 元件
- 元件化方案
-
- 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
kCTMediatorTargetAkCTMediatorActionNativeFetchDetailViewController
中有一個
UIViewController`,
方法可以擷取一個
通過寫
CTMediator
對于子產品A的分類,就可以擷取子產品A中相關的界面以及UI,例如
CTMediator_viewControllerForDetail
。
這樣的優勢在于,沒有了
key-value
的映射關系,不需要維護
url映射表
,更不需要存儲block塊,
Category For A
由開發
子產品A
的人員來寫,他很熟悉
子產品A
(對于他來說将
子產品A
中某個界面取出,并設定相關參數是很簡單的事情),通過分類再轉給不熟悉的人(無需關心
子產品A
的内容)使用,就很友善了。
對于遠端
url
調用,同樣是通過将
url
解析成對應的動作,例如取某個視圖,推出某個界面。
元件化能讓工程架構更加清晰,每個人負責一個子產品,通過pod導入,互不影響。