一、Massive AppDelegate
- AppDelegate 是應用程式的根物件,它連接應用程式和系統,確保應用程式與系統以及其他應用程式正確的互動,通常被認為是每個 iOS 專案的核心,隨著開發的迭代升級,不斷增加新的功能和業務,它的代碼量也不斷增長,最終導致了 Massive AppDelegate,
- 在復雜 AppDelegate 里修改任何東西的成本都是很高的,因為它將會影響整個 APP,一不留神產生 bug,毫無疑問,保持 AppDelegate 的簡潔和清晰對于健康的 iOS 架構來說是至關重要的,
- AppDelegate 常見的業務代碼如下:
-
- 日志埋點統計資料分析;
-
- 初始化資料存盤系統;
-
- 配置 UIAppearance;
-
- 管理 App Badge 數字;
-
- 管理通知:請求權限,存盤令牌,處理自定義操作,將通知傳播到應用程式的其余部分;
-
- 管理 UI 堆疊配置:選擇初始視圖控制器,執行根視圖控制器轉換;
-
- 管理 UserDefaults:設定首先啟動標志,保存和加載資料;
-
- 管理后臺任務;
-
- 管理設備方向;
-
- 更新位置資訊;
-
- 初始化第三方庫(如分享、日志、第三方登陸、支付),
- 這些臃腫的代碼是反模式的,導致難于維護,顯然支持擴展和測驗這樣的類非常復雜且容易出錯,Massive AppDelegates 與我們經常談的 Massive ViewController 的癥狀非常類似,可以運用相應的解決方案來重構 AppDelegate,但這些 Recipe(方案)需要遵循“單一職責、易于擴展、易于測驗”原則,
二、命令模式 Command Design Pattern
- 命令模式是一種資料驅動的設計模式,屬于行為型模式,請求以命令的形式包裹在物件中,并傳給呼叫物件,呼叫物件尋找可以處理該命令的合適的物件,并把該命令傳給相應的物件,該物件執行命令,因此命令的呼叫者無需關心命令做了什么以及回應者是誰,
- 可以為 AppDelegate 的每一個職責定義一個命令,這個命令的名字自行指定:
// 命令協議
@protocol Command <NSObject>
- (void)execute;
@end
// 初始化第三方庫
@interface InitializeThirdPartiesCommand : NSObject <Command>
@end
// 初始化主視圖
@interface InitializeRootViewControllerCommand : NSObject <Command>
@property (nonatomic, strong) UIWindow *keyWindow;
@end
// 初始化視圖全域配置
@interface InitializeAppearanceCommand : NSObject <Command>
@end
// ...
- 然后定義一個統一呼叫的類 StartupCommandsBuilder 來封裝如何創建命令的詳細資訊,AppDelegate 呼叫這個 builder 去初始化命令并執行這些命令:
@implementation StartupCommandsBuilder
// 回傳陣列,元素為遵守 Command 協議的物件
- (NSArray<id<Command>> *)build {
return @[ [InitializeAppearanceCommand new],
[InitializeRootViewControllerCommand new],
[InitializeThirdPartiesCommand new]];
}
@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[[[StartupCommandsBuilder alloc] init] build] enumerateObjectsUsingBlock:^(id<Command> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj execute];
}];
return YES;
}
- 如果 AppDelegate 需要添加新的職責,則可以創建新的命令,然后把命令添加到 Builder 里而無需去改變 AppDelegate,解決方案滿足單一職責、易于擴展、易于測驗原則,
三、組合設計模式 Composite Design Pattern
- 組合模式又叫部分整體模式,用于把一組相似的物件當作一個單一的物件,組合模式依據樹形結構來組合物件,用來表示部分以及整體層次,這種型別的設計模式屬于結構型模式,它創建了物件組的樹形結構,一個很明顯的例子就是 iOS 里的 UIView 以及它的 subviews,
- 這個想法主要是有一個組裝類和葉子類,每個葉子類負責一個職責,而組裝類負責呼叫所有葉子類的方法:
// 組裝類
@interface CompositeAppDelegate : UIResponder <UIApplicationDelegate>
+ (instancetype)makeDefault;
@end
@implementation CompositeAppDelegate
+ (instancetype)makeDefault {
// 這里要實作單例
return [[CompositeAppDelegate alloc] init];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[PushNotificationAppDelegate new] application:application didFinishLaunchingWithOptions:launchOptions];
[[ThirdPartiesConfiguratorAppDelegate new] application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
@end
- 實作執行具體職責的葉子類:
// 葉子類:推送訊息處理
@interface PushNotificationAppDelegate : UIResponder <UIApplicationDelegate>
@end
// 葉子類:初始化第三方庫
@interface ThirdPartiesConfiguratorAppDelegate : UIResponder <UIApplicationDelegate>
@end
@implementation PushNotificationAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"PushNotificationAppDelegate");
return YES;
}
@end
@implementation ThirdPartiesConfiguratorAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"ThirdPartiesConfiguratorAppDelegate");
return YES;
}
@end
- 在 AppDelegate 通過工廠方法創建組裝類,然后通過它去呼叫所有的方法:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[CompositeAppDelegate makeDefault] application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
- 它滿足我們在開始時提出的所有要求,如果要添加一個新的功能,很容易添加一個葉子類,無需改變 AppDelegate,解決方案滿足單一職責、易于擴展、易于測驗原則,
四、中介者模式 Mediator Design Pattern
- 中介者模式是用來降低多個物件和類之間的通信復雜性,這種模式提供了一個中介類,該類通常處理不同類之間的通信,并支持松耦合,使代碼易于維護,中介者模式屬于行為型模式,
- 讓我們定義 AppLifecycleMediator 將 UIApplication 的生命周期通知底下的監聽者,這些監聽者必須遵循AppLifecycleListener 協議,如果需要監聽者要能擴展新的方法,
@interface APPLifeCycleMediator : NSObject
+ (instancetype)makeDefaultMediator;
@end
@implementation APPLifeCycleMediator {
@private
NSArray<id<AppLifeCycleListener>> * _listeners;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (instancetype)initWithListeners:(NSArray<id<AppLifeCycleListener>> *)listeners {
if (self = [super init]) {
_listeners = listeners;
// 通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onAppWillEnterForeground)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onAppDidEnterBackgroud)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onAppDidFinishLaunching)
name:UIApplicationDidFinishLaunchingNotification
object:nil];
}
return self;
}
// 定義好靜態類方法,初始化所有監聽者
+ (instancetype)makeDefaultMediator {
static APPLifeCycleMediator * mediator;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mediator = [[APPLifeCycleMediator alloc] initWithListeners:@[[VideoListener new], [SocketListener new]]];
});
return mediator;
}
- (void)onAppWillEnterForeground {
[_listeners[1] onAppWillEnterForeground];
}
- (void)onAppDidEnterBackgroud {
[_listeners[0] onAppDidEnterBackgroud];
}
- (void)onAppDidFinishLaunching {
}
@end
- 定義 AppLifecycleListener 協議,以及協議的的實作者:
// 監聽協議
@protocol AppLifeCycleListener <NSObject>
@optional
- (void)onAppWillEnterForeground;
- (void)onAppDidEnterBackgroud;
- (void)onAppDidFinishLaunching;
@end
@interface VideoListener : NSObject <AppLifeCycleListener>
@end
@interface SocketListener : NSObject <AppLifeCycleListener>
@end
@implementation VideoListener
- (void)onAppDidEnterBackgroud {
NSLog(@"停止視頻播放");
}
@end
@implementation SocketListener
- (void)onAppWillEnterForeground {
NSLog(@"開啟長鏈接");
}
@end
- 加入到 AppDelegate 中:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[APPLifeCycleMediator makeDefaultMediator];
return YES;
}
- 這個中介者自動訂閱了所有的事件,AppDelegate 僅僅需要初始化它一次,就能讓它正常作業,每個監聽者都有一個單一職責,很容易添加一個監聽者,而無需改變 Appdelgate 的內容,每個監聽者以及中介者能夠容易的被單獨測驗,
五、總結
- 大多數 AppDelegates 的設計都不太合理,過于復雜并且職責過多,我們稱這樣的類為 Massive App Delegates,
- 通過應用軟體設計模式,Massive App Delegate 可以分成幾個單獨的類,每個類都有單一的責任,可以單獨測驗,這樣的代碼很容易更改維護,因為它不會在應用程式中產生一連串的更改,它非常靈活,可以在將來提取和重用,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/296913.html
標籤:其他
