在描述我們解決組件化關(guān)于接口隔離方法之前,先拋出兩個問題:
??1. 大家如何拆分非業(yè)務(wù)模塊的模塊,比如用戶信息模塊,vip信息模塊等非業(yè)務(wù)模塊。
??2.大家對于接口和模型的理解,如何訪問接口的屬性,以及如何實現(xiàn)KVO監(jiān)聽接口屬性變化(比如我們經(jīng)常使用的RAC操作)。
??3.如何管理那些protocol,怎么在外部調(diào)用那些實現(xiàn)接口的類的方法以及屬性。
一、關(guān)于模塊化的拆分
??目前在我們APP里面,實際上是集合了連個APP,一個是學(xué)生版,一個是教師版。學(xué)生端的功能 是純Native的代碼,教師端的是RN的代碼,但是被集成我們的APP中。教師功能有一些模塊是和學(xué)生端是共用的,比如用戶信息,埋點系統(tǒng),設(shè)置頁面等等。
??由于在之后的版本迭代里面,教師端的功能,會從我們的主APP中遷移出去,但是有些功能在教師端還能用,我們我們必須要實現(xiàn)組件化。下面是我們組件化的簡單結(jié)構(gòu)圖,今天主要是針對關(guān)于user,vip這兩個模塊的抽取進(jìn)行講解。大家主要看框圖上黃色的位置。

下圖是我們根據(jù)上面的拆分方式,加上我們的對業(yè)務(wù)的拆分之后,整理出來的結(jié)構(gòu)。這些代碼目前在pod里面,很大家做組件化一樣,我們使用的也是podspec,具體我就不寫了。

二、關(guān)于接口的設(shè)計
通常情況下,我們在APP中會有一個userManager這個單例去管理我們整個APP中用戶信息變化。然后在userManager實現(xiàn)對應(yīng)的增刪改查,屬性訪問等操作。在做組件化之后,我們有一個userManagerProtocol這個接口包含所有原來userManger相關(guān)屬性和方法,為了能夠讓大家在調(diào)用用戶信息的時候感覺沒有太大的區(qū)別。因為是公司代碼,不方便透露,所有我就寫了一個簡單的demo,來解釋我們的實現(xiàn)。這是改造之前userManger頭文件。
@class YCUser;
@interface YCUserManager : NSObject
@property (nonatomic, assign) BOOL isStudent;
- (NSDictionary *)retunUserInfo;
- (NSString *)returnToken;
// 更新
- (void)updateUserInfo:(NSDictionary *)userInfo;
- (void)updateUserToken:(NSString *)token;
- (YCUser *)returnUser;
@end
改造之后,userManger頭文件,是的什么都沒有了,
@interface YCUserManager : NSObject
@end
但是我們多了一個userManagerProtocol,為了能夠快速訪問到用戶屬性,我們還定義了一個userProtocol,userProtocol這個接口里面的屬性和user里面的屬性保持一致。目的是為了實現(xiàn)在外部和訪問類的姿勢保持一致。 頭文件如下:
@protocol YCUserManagerProtocal <NSObject, BHServiceProtocol>
@property (nonatomic, assign) BOOL isStudent;
- (NSDictionary *)retunUserInfo;
- (NSString *)returnToken;
// 更新
- (void)updateUserInfo:(NSDictionary *)userInfo;
- (void)updateUserToken:(NSString *)token;
- (id<YCUserProtocol>)returnUser;
@end
對于userManger實現(xiàn)類如下:
#import "YCUserManager.h"
#import "YCUserManagerProtocal.h"
#import "YCUser.h"
#import <MJExtension.h>
#import <BeeHive.h>
@BeeHiveService(YCUserManagerProtocal, YCUserManager)
@interface YCUserManager() <YCUserManagerProtocal>
@property (nonatomic, strong) YCUser *studentUser;
@property (nonatomic, strong) NSDictionary *userDict;
@property (nonatomic, copy) NSString *token;
@end
@implementation YCUserManager
@synthesize isStudent = _isStudent;
+ (BOOL)singleton {
return YES;
}
static YCUserManager *_manager = nil;
+ (instancetype)shareInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_manager = [[YCUserManager alloc] init];
});
return _manager;
}
- (void)updateUserInfo:(NSDictionary *)userInfo {
self.userDict = userInfo;
YCUser *user = [YCUser mj_objectWithKeyValues:userInfo];
self.studentUser = user;
self.isStudent = YES;
}
- (void)updateUserToken:(NSString *)token {
self.token = token;
}
- (NSString *)returnToken {
return self.token;
}
- (NSDictionary *)retunUserInfo {
return self.userDict;
}
- (id<YCUserProtocol>)returnUser {
return (id)self.studentUser;
}
@end
大家在上面的文件中會看到#import <BeeHive.h> ,這是阿里出的一個框架,BeeHive是基于Spring的Service理念,雖然可以使模塊間的具體實現(xiàn)與接口解耦,但無法避免模塊對接口類的依賴關(guān)系。在我們的模塊化中主要用這個類實現(xiàn)模塊與接口解耦的功能。在使用這個類的時候,為了能夠找個這個類,需要注冊一下,注冊service姿勢有三種,具體關(guān)于BeeHive的更過功能以及使用姿勢可以看 [https://github.com/alibaba/BeeHive]
1. 通過BeeHiveService宏進(jìn)行Annotation標(biāo)記。
@BeeHiveService(YCUserManagerProtocal, YCUserManager)
2. 讀取本地Pilst文件
[BHContext shareInstance].serviceConfigName = @"BeeHive.bundle/BHService";
3.Load方法注冊
[[BeeHive shareInstance] registerService:@protocol(YCUserManagerProtocal) service:[YCUserManager class]];
三、關(guān)于接口管理以及使用
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *dict = @{
@"name":@"周文超",
@"age":@(12),
@"student" : @{
@"studentName" : @"李向紅",
@"studentAge" : @(11)
}
};
id<YCUserManagerProtocal> userManager = [[BeeHive shareInstance] createService:@protocol(YCUserManagerProtocal)];
// 更新數(shù)據(jù)
[userManager updateUserInfo:dict];
[RACObserve(userManager, isStudent) subscribeNext:^(id x) {
}];
// 獲取用戶信息
id<YCUserProtocol> user = [userManager returnUser];
[userManager updateUserToken:@"我是token"];
NSLog(@"%@----%@-----%@", user.name, [userManager returnToken], [user.student mj_JSONObject]);
[RACObserve(user, name) subscribeNext:^(id _Nullable x) {
}];
}
先看代碼,對著代碼進(jìn)行講解。
id<YCUserManagerProtocal> userManager = [[BeeHive shareInstance] createService:@protocol(YCUserManagerProtocal)];
在BeeHive中是通過BHServiceManager來管理各個Protocol的。BHServiceManager中只會管理已經(jīng)被注冊過的Protocol。上面我們對YCUserManagerProtocal進(jìn)行了注冊。因此我們可以通過這種方式獲取到我們注冊的service。
大家可能疑惑為什么,對于一個接口的屬性可以實現(xiàn)KVO操作,這也是OC的特性。protocol 的本質(zhì)類似一個抽象類,這個聲明了一些純虛方法或者屬性。在java中,這個叫接口類在編碼中,通過繼承協(xié)議,實現(xiàn)了協(xié)議中描述的這一套方法或者方法賦值操作。我們在接口里面定義了一個isStudent屬性,在實現(xiàn)類里面,我們做了
@synthesize isStudent = _isStudent;
所以我們可以實現(xiàn)對它的監(jiān)聽,同樣,我們通過
// 獲取user
id<YCUserProtocol> user = [userManager returnUser];
[RACObserve(userManager, isStudent) subscribeNext:^(id x) {
}];
// 監(jiān)聽user屬性變化
[RACObserve(user, name) subscribeNext:^(id _Nullable x) {
}];
注意:大家需要注意的幾點
- 在使用BeeHive的時候一定要注冊
- 如果要想某個服務(wù)是單利,需要重寫下面這個方法
+ (BOOL)singleton {
return YES;
}
3.對于實現(xiàn)接口的類,大家在做模型轉(zhuǎn)json的時候,會附帶幾個protocol的四個屬性,hash, superclass, debugDescription, description