組件
從功能業務角度上看不能在查分,適可替換,可復用的.
模塊
有多個組件組成,他可以實現一個獨立的功能,一個或多個業務.
例如大眾點評的美食功能是一個業務,也可以叫做"美食模塊".
模塊化開發 中介者
//Mediator.m 中間件代碼
@implementation Mediator
+ (UIViewController *)OpenViewController1:(NSString *)viewId {
Class cls = NSClassFromString(@"UIViewController1");
return [cls performSelector:NSSelectorFromString(@"viewController1:") withObject:@{@"viewId": viewId}];
}
+ (UIViewController *) OpenViewController2:(NSString *) viewId type:(NSInteger)type {
Class cls = NSClassFromString(@"UIViewController2");
return [cls performSelector:NSSelectorFromString(@"viewController2:") withObject:@{@"viewId": viewId, @"type": @(type)}];
}
@end
//調用者
#import "Mediator.h"
@implementation ViewController
- (void)gotoViewController1 {
UIViewController * vc = [Mediator OpenViewController1:@"id" ];
[self.navigationController pushViewController: vc animated:YES];
}
- (void) gotoViewController2 {
UIViewController * vc = [Mediator OpenViewController1:@"id" type:1 ];
[self.navigationController pushViewController: vc animated:YES];
}
@end
這樣在調用里面就不用引用 UIViewController1和 UIViewController1 的頭文件了 就不會產生相互依賴 只要在調用其他組件的時候引入 Mediator.h 就可以了.接下來就是優化這套寫法,有兩個優化點:
1.Mediator 每一個方法里都要寫 runtime 方法,格式是確定的,這是可以抽取出來的。
2.每個組件對外方法都要在 Mediator 寫一遍,組件一多 Mediator 類的長度是恐怖的。
蘑菇街為了補全本地調用的功能,為組件多加了另一種方案,就是通過 protocol-class 注冊表的方式。(感覺比上面的方案要復雜很多)
首先有一個新的中間件:
//ProtocolMediator.m 新中間件
@implementation ProtocolMediator
@property (nonatomic, storng) NSMutableDictionary *protocolCache
//注冊協議協議
- (void)registerProtocol:(Protocol *)proto forClass:(Class)cls {
NSMutableDictionary *protocolCache;
[protocolCache setObject:cls forKey:NSStringFromProtocol(proto)];
}
- (Class)classForProtocol:(Protocol *)proto {
return protocolCache[NSStringFromProtocol(proto)];
}
@end
然后有一個公共Protocol文件,定義了每一個組件對外提供的接口:
//ComponentProtocol.h
@protocol BookDetailComponentProtocol <NSObject>
- (UIViewController *)bookDetailController:(NSString *)bookId;
- (UIImage *)coverImageWithBookId:(NSString *)bookId;
@end
@protocol ReviewComponentProtocol <NSObject>
- (UIViewController *)ReviewController:(NSString *)bookId;
@end
再在模塊里實現這些接口,并在初始化時調用 registerProtocol 注冊。
//BookDetailComponent 組件
#import "ProtocolMediator.h"
#import "ComponentProtocol.h"
#import "WRBookDetailViewController.h"
+ (void)initComponent
{
[[ProtocolMediator sharedInstance] registerProtocol:@protocol(BookDetailComponentProtocol) forClass:[self class];
}
- (UIViewController *)bookDetailController:(NSString *)bookId {
WRBookDetailViewController *detailVC = [[WRBookDetailViewController alloc] initWithBookId:param[@"bookId"]];
return detailVC;
}
- (UIImage *)coverImageWithBookId:(NSString *)bookId {
….
}
最后調用者通過 protocol 從 ProtocolMediator 拿到提供這些方法的 Class,再進行調用:
//WRReadingViewController.m 調用者
//ReadingViewController.m
#import "ProtocolMediator.h"
#import "ComponentProtocol.h"
+ (void)gotoDetail:(NSString *)bookId {
Class cls = [[ProtocolMediator sharedInstance] classForProtocol:BookDetailComponentProtocol];
id bookDetailComponent = [[cls alloc] init];
UIViewController *vc = [bookDetailComponent bookDetailController:bookId];
[[UIApplication sharedApplication].keyWindow.rootViewController.navigationController pushViewController:vc animated:YES];
}