組件
從功能業(yè)務(wù)角度上看不能在查分,適可替換,可復(fù)用的.
模塊
有多個(gè)組件組成,他可以實(shí)現(xiàn)一個(gè)獨(dú)立的功能,一個(gè)或多個(gè)業(yè)務(wù).
例如大眾點(diǎn)評(píng)的美食功能是一個(gè)業(yè)務(wù),也可以叫做"美食模塊".
模塊化開發(fā) 中介者
//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
//調(diào)用者
#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
這樣在調(diào)用里面就不用引用 UIViewController1和 UIViewController1 的頭文件了 就不會(huì)產(chǎn)生相互依賴 只要在調(diào)用其他組件的時(shí)候引入 Mediator.h 就可以了.接下來就是優(yōu)化這套寫法,有兩個(gè)優(yōu)化點(diǎn):
1.Mediator 每一個(gè)方法里都要寫 runtime 方法省古,格式是確定的典予,這是可以抽取出來的食磕。
2.每個(gè)組件對(duì)外方法都要在 Mediator 寫一遍,組件一多 Mediator 類的長度是恐怖的鲁捏。
蘑菇街為了補(bǔ)全本地調(diào)用的功能低匙,為組件多加了另一種方案,就是通過 protocol-class 注冊(cè)表的方式亚兄。(感覺比上面的方案要復(fù)雜很多)
首先有一個(gè)新的中間件:
//ProtocolMediator.m 新中間件
@implementation ProtocolMediator
@property (nonatomic, storng) NSMutableDictionary *protocolCache
//注冊(cè)協(xié)議協(xié)議
- (void)registerProtocol:(Protocol *)proto forClass:(Class)cls {
NSMutableDictionary *protocolCache;
[protocolCache setObject:cls forKey:NSStringFromProtocol(proto)];
}
- (Class)classForProtocol:(Protocol *)proto {
return protocolCache[NSStringFromProtocol(proto)];
}
@end
然后有一個(gè)公共Protocol文件,定義了每一個(gè)組件對(duì)外提供的接口:
//ComponentProtocol.h
@protocol BookDetailComponentProtocol <NSObject>
- (UIViewController *)bookDetailController:(NSString *)bookId;
- (UIImage *)coverImageWithBookId:(NSString *)bookId;
@end
@protocol ReviewComponentProtocol <NSObject>
- (UIViewController *)ReviewController:(NSString *)bookId;
@end
再在模塊里實(shí)現(xiàn)這些接口采驻,并在初始化時(shí)調(diào)用 registerProtocol 注冊(cè)审胚。
//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 {
….
}
最后調(diào)用者通過 protocol 從 ProtocolMediator 拿到提供這些方法的 Class,再進(jìn)行調(diào)用:
//WRReadingViewController.m 調(diào)用者
//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];
}