iOS VIPER架構實踐(三):面向介面的路由設計
路由是實現模組間解耦的一個有效工具。如果要進行元件化開發,路由是必不可少的一部分。目前iOS上絕大部分的路由工具都是基於URL匹配的,優缺點都很明顯。這篇文章裡將會給出一個更加原生和安全的設計,這個設計的特點是:
- 路由時用protocol尋找模組
- 可以對模組進行固定的依賴注入和執行時依賴注入
- 支援不同模組間進行介面適配和轉發,因此無需和某個固定的protocol關聯
- 充分解耦的同時,增加型別安全
- 支援移除已執行的路由
- 封裝UIKit介面跳轉方法,可以一鍵跳轉和移除
- 支援storyboard,支援其他任意模組
- 可以檢測介面跳轉時的大部分錯誤
如果你想要一個能夠充分解耦、型別安全、有依賴注入功能的路由器,那這個就是目前所能找到的最佳方案。
這個路由工具是為了實踐VIPER模式而設計的,目的是為VIPER提供依賴注入功能,不過它也可以用於MVC、MVP、MVVM,沒有任何限制。
Router的作用
首先,我們需要梳理清楚,為什麼我們需要Router,Router能帶來什麼好處,解決什麼問題?我們需要一個什麼樣的Router?
路由缺失時的情況
沒有路由時,介面跳轉的程式碼就很容易產生模組間耦合。
iOS中執行介面跳轉時,用的是UIViewController上提供的跳轉方法:
[sourceViewController.navigationController pushViewController:destinationViewController animated:YES] ;
[sourceViewController presentViewController:destinationViewController animated:YES completion:nil];
如果是直接匯入destinationViewController的標頭檔案進行引用,就會導致和destinationViewController模組產生耦合。類似的,一個模組引用另一個模組時也會產生這樣的耦合。因此我們需要一個方式來獲取destinationViewController,但又不能對其產生直接引用。
這時候就需要路由提供的"尋找模組"的功能。以某種動態的方式獲取目的模組。
那麼路由是怎麼解決模組耦合的呢?在上一篇VIPER講解裡,路由有這幾個主要職責:
- 尋找指定模組,執行具體的路由操作
- 宣告模組的依賴
- 宣告模組的對外介面
- 對模組內各部分進行依賴注入
通過這幾個功能,就能實現模組間的完全解耦。
尋找模組
路由最重要的功能就是給出一種尋找某個指定模組的方案。這個方案是鬆耦合的,獲取到的模組在另一端可以隨時被另一個相同功能的模組替換,從而實現兩個模組之間的解耦。
尋找模組的實現方式其實只有有限的幾種:
- 用一個字串identifier來標識某個對應的介面(URL Router、UIStoryboardSegue)
- 利用Objective-C的runtime特性,直接呼叫目的模組的方法(CTMediator)
- 用一個protocol來和某個介面進行匹配(蘑菇街的第二種路由和阿里的BeeHive),這樣就可以更安全的對目的模組進行傳參
這幾種方案的優劣將在之後逐一細說。
宣告依賴和介面
一個模組A有時候需要使用其他模組的功能,例如最通用的log功能,不同的app有不同的log模組,如果模組A對通用性要求很高,log方法就不能在模組A裡寫死,而是應該通過外部呼叫。這時這個模組A就依賴於一個log模組了。App在使用模組A的時候,需要知道它的依賴,從而在使用模組A之前,對其注入依賴。
當通過cocoapods這樣的包管理工具來配置不同模組間的依賴時,一般模組之間是強耦合的,模組是一一對應的,當需要替換一個模組時會很麻煩,容易牽一髮而動全身。如果是一個單一功能模組,的確需要依賴其他特定的各種庫時,那這樣做沒有問題。但是如果是一個業務模組中引用了另一個業務模組,就應該儘量避免互相耦合。因為不同的業務模組一般是由不同的人負責,應該避免出現一個業務模組的簡單修改(例如調整了方法或者屬性的名字)導致引用了它的業務模組也必須修改的情況。
這時候,業務模組就需要在程式碼裡宣告自己需要依賴的模組,讓app在使用時提供這些模組,從而充分解耦。
示例程式碼:
@protocol ZIKLoginServiceInput <NSObject>
- (void)loginWithAccount:(NSString *)account
password:(NSString *)password
success:(void(^_Nullable)(void))successHandler
error:(void(^_Nullable)(void))errorHandler;
@end
@interface ZIKNoteListViewController ()
//筆記介面需要登入後才能檢視,因此在標頭檔案中宣告,讓外部在使用的時候設定此屬性
@property (nonatomic, strong) id<ZIKLoginServiceInput> loginService;
@end
這個宣告依賴的工作其實是模組的Builder的職責。一個介面模組大部分情況下都不止有一個UIViewController,也有其他一些Manager或者Service,而這些角色都是有各自的依賴的,都統一由模組的Builder宣告,再在Builder內部設定依賴。不過在上一篇文章的VIPER講解裡,我們把Builder的職責也放到了Router裡,讓每個模組單獨提供一個自己的Router。因此在這裡,Router是一個離散的設計,而不是一個單例Router掌管所有的路由。這樣的好處就是每個模組可以充分定製和控制自己的路由過程。
可以宣告依賴,也就可以同時宣告模組的對外介面。這兩者很相似,所以不再重複說明。
Builder和依賴注入
執行路由的同時用Builder進行模組構建,構建的時候就對模組內各個角色進行依賴注入。當你呼叫某個模組的時候,需要的不是某個簡單的具體類,而是一個構建完畢的模組中的某個具體類。在使用這個模組前,模組需要做一些初始化的操作,比如VIPER裡設定各個角色之間的依賴關係,就是一個初始化操作。因此使用路由去獲取某個模組中的類,必定需要通過模組的Builder進行。很多路由工具都缺失了這部分功能。
你可以把依賴注入簡單地看成對目的模組傳參。在進行介面跳轉和使用某個模組時,經常需要設定目的模組的一些引數,例如設定delegate回撥。這時候就必須呼叫一些目的模組的方法,或者傳遞一些物件。由於每個模組需要的引數都不一樣,目前大部分Router都是使用字典包裹引數進行傳遞。但其實還有更好、更安全的方案,下面將會進行詳解。
你也可以把Router、Builder和Dependency Injector分開,不過如果Router是一個離散型的設計,那麼都交給各自的Router去做也很合理,同時能夠減少程式碼量,也能夠提供細粒度的AOP。
現有的Router
梳理完了路由的職責,現在來比較一下現有的各種Router方案。關於各個方案的具體實現細節我就不再展開看,可以參考這篇詳解的文章:iOS 元件化 —— 路由設計思路分析。
URL Router
目前絕大多數的Router都是用一串URL來表示需要開啟的某個介面,程式碼上看來大概是這樣:
//註冊某個URL,和路由處理進行匹配儲存
[URLRouter registerURL:@"settings" handler:^(NSDictionary *userInfo) {
UIViewController *sourceViewController = userInfo[@"sourceViewController"];
//獲取其他引數
id param = userInfo[@"param"];
//獲取需要的介面
UIViewController *settingViewController = [[SettingViewController alloc] init];
[sourceViewController.navigationController pushViewController: settingViewController animated:YES];
}];
//呼叫路由
[URLRouter openURL:@"myapp://noteList/settings?debug=true" userInfo:params completion:^(NSDictionary *info) {
}];
傳遞一串URL就能開啟noteList介面的settings介面,用字典包裹需要傳遞的引數,有時候還會把UIKit的push、present等方法進行簡單封裝,提供給呼叫者。
這種方式的優點和缺點都很突出。
優點
極高的動態性
這是動態性最高的方案,甚至可以在執行時隨時修改路由規則,指向不同的介面。也可以很輕鬆地支援多級頁面的跳轉。
如果你的app是電商類app,需要經常做活動,app內的跳轉規則經常變動,那麼就很適合使用URL的方案。
統一多端路由規則
URL的方案是最容易跨平臺實現的,iOS、Andorid、web、PC都按照URL來進行路由時,也就可以統一管理多端的路由規則,降低多端各自維護和修改的成本,讓不懂技術的運營人員也可以簡單快速地修改路由。
和上一條一樣,這也是一個和業務強相關的優點。如果你有統一多端的業務需求,使用URL也很合適。
適配URL scheme
iOS中的URL scheme可以跨程序通訊,從app外開啟app內的某個指定頁面。當app內的頁面都能使用URL開啟時,也就直接相容了URL scheme,無需再做額外的工作。
缺點
不適合通用模組
URL Router的設計只適合UI模組,不適合其他功能性模組的元件。功能性模組的呼叫並不需要如此強的動態特性,除非是有模組熱更新的需求,否則一個模組的呼叫在一個版本里應該總是穩定不變的,即便要進行模組間解耦,也不應該用這種方式。
安全性差
字串匹配的方式無法進行編譯時檢查,當頁面配置出錯時,只能在執行時才能發現。如果某個開發人員不小心在字串里加了一個空格,編譯時也無法發現。你可以用巨集定義來減少這種出錯的機率。
維護困難
沒有高效地宣告介面的方式,只能從文件裡查詢,編寫時必須仔細對照字串及其引數型別。
傳參通過字典來進行,引數型別無法保證,而且也無法準確地知道所呼叫的介面需要哪些引數。當目的模組進行了介面升級,修改了引數型別和數量,那所有用到的地方都要一一修改,並且沒有編譯器的幫助,你無法知道是否遺漏了某些地方。這將會給維護和重構帶來極大的成本。
針對這個問題,蘑菇街的選擇是用另一個Router,用protocol來獲取目的模組,再進行呼叫,增加安全性。
Protocol Router
這個方案也很容易理解。把之前的字串匹配改成了protocol匹配,就能獲取到一個實現了某個protocol的物件。
開源方案裡只看到了BeeHive實現了這樣的方式:
id<ZIKLoginServiceInput> loginService = [[BeeHive shareInstance] createService:@protocol(ZIKLoginServiceInput)];
優點
安全性好,維護簡單
再對這個物件呼叫protocol中的方法,就十分安全了。在重構和修改時,有了編譯器的型別檢查,效率更高。
適用於所有模組
Protocol更加符合OC和Swift原生的設計思想,任何模組都可以使用,而不侷限於UI模組。
優雅地宣告依賴
模組A需要用到登入模組,但是它要怎麼才能宣告這種依賴關係呢?如果使用Protocol Router,那就只需要在標頭檔案裡定義一個屬性:
@property (nonatomic, string) id<ZIKLoginServiceInput> *loginService;
如果這個依賴是必需依賴,而不是一個可選依賴,那就新增到初始化引數裡:
@interface ModuleA ()
- (instancetype)initWithLoginService:(id<ZIKLoginServiceInput>)loginService;
@end
問題是,如果這樣的依賴很多,那麼初始化方法就會變得很長。因此更好的做法是由Builder進行固定的依賴注入,再提供給外部。目前BeeHive並沒有提供依賴注入的功能。
缺點
動態性有限
你可以維護一份protocol和模組的對照表,使用動態的protocol來嘗試動態地更改路由規則,也可以在Protocol Router之上封裝一層URL Router專門用於動態性的需求。
需要額外適配URL Scheme
使用了Protocol Router就需要再額外處理URL Scheme了。不過這樣也是正常的,解析URL Scheme本來就應該放到另一個單獨的模組裡。
Protocol是否會導致耦合?
很多談到這種方案的文章都會指出,和URL Router相比,Protocol Router會導致呼叫者引用目的模組的protocol,因此會產生"耦合"。我認為這是對"解耦"的錯誤理解。
要想避免耦合,首先要弄清楚,我們需要什麼程度的解耦。我的定義是:模組A呼叫了模組B,模組B的介面或者實現在做出簡單的修改時,或者模組B被替換為相同功能的模組C時,模組A不需要進行任何修改。這時候就可以認為模組A和模組B是解耦的。
業務設計的互相關聯
有些時候,表達出兩個模組之間的關聯是有意義的。
當一個介面A需要展示一個登入介面時,它可能需要向登入介面傳遞一個"提示語"引數,用於在登入介面顯示一串提示。這時候,介面A在呼叫登入介面時,是要求登入介面能夠顯示這個自定義提示語的,在業務設計中就存在兩個模組間的強關聯性。這時候,URL Router和Protocol Router沒有任何區別,包括下面將要提到的Target-Action
路由方式,都存在耦合,但是Protocol
Router通過簡單地改善,是可以把這部分耦合去除的。
URL Router:
[URLRouter openURL:@"login" userInfo:@{@"message":@"請登入檢視筆記詳情"}];
Protocol Router:
@protocol LoginViewInput <NSObject>
@property (nonatomic, copy) NSString *message;
@end
//獲取登入介面進行設定
UIViewController<LoginViewInput> *loginViewController = [ProtocolRouter destinationForProtocol:@protocol(LoginViewInput)];
loginViewController.message = @"請登入檢視筆記詳情";
由於字典傳參的原因,URL Router只不過是把這種介面上的關聯隱藏到了字典key裡,它在引數字典裡使用@"message"
時,就是在隱式地使用LoginViewInput
的介面。
這種業務設計上導致的模組之間互相關聯是不可避免的,也是不需要去隱藏的。隱藏了反而會引來麻煩。如果登入介面的屬性名字變了,從NSString *message
改成了NSString
*notifyString
,那麼URL Router在register的時候也必須修改傳參時的程式碼。如果register是由登入介面自己執行和處理的,而不是由App Context來處理的,那麼此時引數key是固定為@"notifyString"
的,那就會要求所有呼叫者的傳參key也修改為notifyString
,這種修改如果缺少編譯器的幫助會很危險,目前是用巨集來減少這種修改導致的工作量。而Protocol
Router在修改時就能充分利用編譯器進行檢查,能夠保證100%安全。
因此,URL Router並不能做到解耦,只是隱藏了介面關聯而已。一旦遇到了需要修改或者重構的情況,麻煩就出現了,在替換巨集的時候,你還必須仔細檢查有沒有哪裡有直接使用字串的key。只是簡單地修改名字還是可控的,如果是需要增加引數呢?這時候就根本無法檢查哪裡遺漏了引數傳遞了。這就是字典傳參的壞處。
關於這部分的討論,也可以參考Peak大佬的文章:iOS元件化方案。
Protocol Router在這種情況下也需要作出修改,但是它能幫助你安全高效地進行重構。而且只要稍加改進,也可以完全無需修改。解決方法就是把Protocol分離為Required
Interface
和Provided Interface
。
Required Interface
和 Provided
Interface
模組的介面其實是有Required Interface
和Provided
Interface
的區別的。Required Interface
就是呼叫者需要用到的介面,Provided
Interface
就是實際的被呼叫者提供的介面。
在UML的元件圖中,就很明確地表現出了這兩者的概念。下圖中的半圓就是Required
Interface
,框外的圓圈就是Provided Interface
:
那麼如何實施Required Interface
和Provided
Interface
?上一篇文章裡已經討論過,應該由App Context在一個adapter裡進行介面適配,從而使得呼叫者可以繼續在內部使用Required
Interface
,adapter負責把Required Interface
和修改後的Provided
Interface
進行適配。
示例程式碼:
@protocol ModuleARequiredLoginViewInput <NSObject>
@property (nonatomic, copy) NSString *message;
@end
//Module A中的呼叫程式碼
UIViewController<ModuleARequiredLoginViewInput> *loginViewController = [ZIKViewRouterToView(LoginViewInput) makeDestination];
loginViewController.message = @"請登入檢視筆記詳情";
//Login Module Provided Interface
@protocol ProvidedLoginViewInput <NSObject>
@property (nonatomic, copy) NSString *notifyString;
@end
//App Context 中的 Adapter,用Objective-C的category或者Swift的extension進行介面適配
@interface LoginViewController (ModuleAAdapte) <ModuleARequiredLoginViewInput>
@property (nonatomic, copy) NSString *message;
@end
@implementation LoginViewController (ModuleAAdapte)
- (void)setMessage:(NSString *)message {
self.notifyString = message;
}
- (NSString *)message {
return self.notifyString;
}
@end
用category、extension、NSProxy等技術相容新舊介面,工作全部由模組的使用和裝配者App Context
完成。如果LoginViewController
已經有了自己的message
屬性,這時候就說明新的登入模組是不可相容的,必須有某一方做出修改。當然,介面適配能做的事情是有限的,例如一個介面從同步變成了非同步,那麼這時候兩個模組也是不能相容的。
因此,如果模組需要進行解耦,那麼它的介面在設計的時候就應該十分仔細,儘量不要在引數中引入太多其他的模組依賴。
只有存在Required Interface
和Provided
Interface
概念的設計,才能做到徹底的解耦。目前的路由方案都缺失了這一部分。
Target-Action
CTMediator的方案,把對模組的呼叫封裝到Target-Action中,利用了Objective-C的runtime特性,省略了Target-Action的註冊和繫結工作,直接通過CTMediator中介者呼叫目的模組的方法。
@implementation CTMediator (CTMediatorModuleAActions)
- (UIViewController *)CTMediator_viewControllerForDetail
{
UIViewController *viewController = [self performTarget:kCTMediatorTargetA
action:kCTMediatorActionNativFetchDetailViewController
params:@{@"key":@"value"}
shouldCacheTarget:NO
];
if ([viewController isKindOfClass:[UIViewController class]]) {
// view controller 交付出去之後,可以由外界選擇是push還是present
return viewController;
} else {
// 這裡處理異常場景,具體如何處理取決於產品
return [[UIViewController alloc] init];
}
}
@end
-performTarget:action:params:shouldCacheTarget:
方法通過NSClassFromString
,獲取目的模組提供的Target類,再呼叫Target提供的Action,實現了方法呼叫:
@implementation CTMediator
- (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget
{
NSString *targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
NSString *actionString = [NSString stringWithFormat:@"Action_%@:", actionName];
Class targetClass;
NSObject *target =
相關推薦
iOS VIPER架構實踐(三):面向介面的路由設計
路由是實現模組間解耦的一個有效工具。如果要進行元件化開發,路由是必不可少的一部分。目前iOS上絕大部分的路由工具都是基於URL匹配的,優缺點都很明顯。這篇文章裡將會給出一個更加原生和安全的設計,這個設計的特點是:
路由時用protocol尋找模組可以對模
中小型研發團隊架構實踐三要點--轉
架構圖 tput 驗證 簡單 put 目的 flux 商務 限流 來自微信公眾號聊聊架構
作者|張輝清
編輯|雨多田光
如果你正好處在中小型研發團隊……
中小型研發團隊很多,而社區在中小型研發團隊架構實踐方面的探討卻很少。中
LAMP原理架構解析(三):LAMP編譯安裝
mariadbCentos7.3編譯安裝LAMP目錄:編譯環境LAMP編譯安裝一.環境準備 征信數據庫數據事件不一致導致數據(RAC集群)混亂,PLSQL查詢時間和數據庫時間不一致,嚴重影響業務本文出自 “每天進步一點點,自律” 博客,請務必保留此出處http://wbxue.blog.51cto.
C語言面向物件程式設計:面向介面程式設計(4)
Java 中有 interface 關鍵字,C++ 中有抽象類或純虛類可以與 interface 比擬,C 語言中也可以實現類似的特性。
在面試 Java 程式設計師時我經常問的一個問題是:介面和抽象類有什麼區別。
&n
架構系列三:使用Keepalived+Nginx+tomcat實現叢集部署
在前面的一篇文章《架構系列二:使用Nginx+tomcat實現叢集部署》,介紹了通過Nginx配置Tomct叢集,當其中一個Tomcat服務停止後,Nginx可自動識別並選擇另一個伺服器響應使用者請求,達到了Tomcat叢集的效果,那如果Nginx伺服器停掉後,
實踐三:使用谷歌物體檢測API訓練自己的資料集
一.環境安裝:
ubuntu
1:TensorFlow環境二選一:
親測用使用公開資料CPU需要在i5下跑一晚上,GPU只要30分鐘,建議安裝TensorFlow 1.00
pip install tensorflow # For CPU
pip in
C#進階系列——MEF實現設計上的“鬆耦合”(終結篇:面向介面程式設計)
序:忙碌多事的八月帶著些許的倦意早已步入尾聲,金秋九月承載著抗戰勝利70週年的喜慶撲面而來。沒來得及任何準備,似乎也不需要任何準備,因為生活不需要太多將來時。每天忙著上班、加班、白加班,忘了去憤,忘了去算計所謂的價值。天津爆炸事故時刻警示著我們生命的無常,逝者安息,活著的人生活還得繼續,珍惜生命,遠離傷害。武
iOS音訊學習筆記三:音訊會話管理
使用Audio Session API ,可以指定App需要的音訊行為,比如,當播放音訊時,使得其他應用App靜音或者混和在一起,也可以指定當App的音訊被中斷(例如被電話)時的行為,還可以讓App響應使用者的行為,比如插入或拔出耳機,或者響應那些使用聲音硬體的事件,比如Clock、日曆鬧鐘或者
C語言面向物件程式設計(四):面向介面程式設計
Java 中有 interface 關鍵字,C++ 中有抽象類或純虛類可以與 interface 比擬,C 語言中也可以實現類似的特性。
在面試 Java 程式設計師時我經常問的一個問題是:介面和抽象類有什麼區別。
很多程式設計書籍也經常說要面向介面
Java設計第一原則:面向介面程式設計
在專案中的意義:
在傳統的專案開發過程中,由於客戶的需求經常變化,如果不採用面向介面程式設計,那麼我們必須不停改寫現有的業務程式碼。改寫程式碼可能產生新的BUG,而且改寫程式碼還會影響到呼叫該業務的類,可能全都需要修改,影響系統本身的穩定性。而且為了將改寫程式碼帶來的影響最小,我們不得不屈服當前的系
記一次介面效能優化實踐總結:優化介面效能的八個建議
### 前言
最近對外介面偶現504超時問題,原因是程式碼執行時間過長,超過nginx配置的15秒,然後真槍實彈搞了一次介面效能優化。在這裡結合優化過程,總結了介面優化的八個要點,希望對大家有幫助呀~
- 資料量比較大,批量操作資料入庫
- 耗時操作考慮非同步處理
- 恰當使用快取
- 優化程式邏輯、程式碼
32-高級路由:BGP匯總:實驗三: null 0路由匯總
cto 9.1 via null ffffff router color fig ip route 一、實驗拓撲:二、實驗要求:1、R1部署192.168.8.1~192.168.11.1環回口;2、R1上部署192.168.8.0/22 null 0,並將此路由在BGP進
機器學習實踐心得:數據平臺設計與搭建US幸運飛艇平臺出租
git 要花 規範 支持 避免 取數據 用戶 硬件 app 機器學習作為近幾年的一項熱門技術US幸運飛艇平臺出租QQ2952777280【話仙源碼論壇】hxforum.com【木瓜源碼論壇】papayabbs.com,不僅憑借眾多“人工智能”產品而為人所熟知,更是從根本上增
Android實時監控專案第二篇:登陸介面的設計
在開始核心功能的實現之前,我們先從最簡單的部分開始,設計第一個Activity介面,它主要用來獲取使用者輸入的需要連線的PC端的IP地址。
該Activity對應的XML佈局檔案很簡單,就不詳細解釋了,如下:
<TableLayoutxml
MVC系列——MVC原始碼學習:打造自己的MVC框架(三:自定義路由規則)
前言:上篇介紹了下自己的MVC框架前兩個版本,經過兩天的整理,版本三基本已經完成,今天還是發出來供大家參考和學習。雖然微軟的Routing功能已經非常強大,完全沒有必要再“重複造輪子”了,但博主還是覺得自己動手寫一遍印象要深刻許多,希望想深入學習MVC的童鞋自己動手寫寫。好了,廢話就此打住。
MVC原始
【遠端呼叫框架】如何實現一個簡單的RPC框架(五)優化三:軟負載中心設計與實現
【如何實現一個簡單的RPC框架】系列文章:
1.前言
在部落格【遠端呼叫框架】如何實現一個簡單的RPC框架(一)想法與設計中我們介紹了“服務註冊查詢中心”,負責服務資訊的管理即服務的註冊以及查詢,在目前為止的實現中,我們採用web應用的方式,以
java設計模式:面向對象設計的7個原則
ron 依賴倒置原則 步驟 計算機 適應性 抽象類 oops 關閉 sla 在軟件開發中,為了提高軟件系統的可維護性和可復用性,增加軟件的可擴展性和靈活性,程序員要盡量根據7條原則來開發程序,從而提高軟件開發效率,節約軟件開發成本和維護成本。
這7條原則分別是:開閉原則、
基於大中臺架構的電商業務中臺最佳實踐之三:交易中臺技術要點設計之高效能
接著上篇繼續講,接下來主要介紹交易總體設計的技術要點設計,對於電商中臺來說,交易系統是核心中的核心,一開始就需要圍繞高效能,高可用,和高擴充套件三個方面來重點設計。本篇主要介紹高效能設計。
對於高效能的定義,通常可以理解為系統/服務介面響應時間低(rt)且併發量(qps,tps)高. 提
SoC嵌入式軟件架構設計之三:代碼分塊(Bank)設計原則
post 介紹 讀寫 cor 層次 clas rom bank 分配
上一節講述了在沒有MMU的CPU(如80251、MIPS M控制器系列、ARM cortex m系列)上實現虛擬內存管理的集成硬件設計方法。新設計的內存管理管理單元要實現虛擬內存管理還須要
微服務理論與實踐(三)-微服務架構的基本能力和優缺點
控制臺 並且 提高 str love 速度 ont 寫入 框架 1.微服務架構模式方案
微服務架構采用Scale Cube方法設計應用架構,將應用服務按功能拆分成一組相互協作的服務。每個服務負責一組特定、相關的功能。每個服務可以有自己獨立的數據庫,從而保證與其他服務解耦。