假設要實現一個給客戶發送提示消息的功能,發送的消息類型可分爲:普通消息、加急消息、特加急消息等等,而每種消息的發送的方式通常有:系統內推送、手機短信、電子郵件等等。若是讓咱們來實現,會怎麼作呢?javascript
咱們先來實現一個簡單的版本,使用系統推送和電子郵件發送普通消息,實現起來不叫簡單,就不展現代碼了,直接看UML結構圖java
很簡單的實現對吧,如今再增長一個加急消息的發送,也是經過系統推送和Email兩種方式發送,並且加急消息還額外多了一個方法,想了想簡單嘛,直接擴展示有的接口不就能夠了嗎,此時UML結構如以下:編程
若是在增長一個特加急消息的發送呢,也是兩種方式,也有一個額外的方法,繼續擴展嘛,此時UML機構如以下:app
是否是感受類的數目劇增了,還沒完呢。如今須要給每種消息類型增長一種發送方式:手機發送。繼續改,UML結構圖以下:測試
此時類的數目已經很是多了,若是繼續增長消息類型或者發送方式,那麼又要重複擴展,類的數目會急劇增長。atom
咱們來仔細分析下上面的實現,其實這裏面有兩個變化的維度:消息類型和發送方式。他們之間是交織在一塊兒的,以下圖所示:spa
因爲這兩個維度是交織在一塊兒,那麼他們之間的組合方式就有9種,也就是咱們上面看到的有9個類,若是此時任何一個維度發生變化,都會致使與之關聯的另外一個維度也須要修改。並且一個維度的上的數目的增長,都會致使總體類的數目成倍數的增長。若是消息的發送類型和發送方式都有10種的話,那麼就須要實現100個類,想一想就恐怖。3d
那麼天然而然的咱們就想到把這兩個維度分開,讓他們獨自變化,互不影響,須要用的是會把他們組合在一塊兒就好了。這樣一個維度的類增長,不會致使另外一個維度類也須要跟着一塊兒增長。code
再次證實:多用組合少用繼承cdn
那麼如何實現呢?這就要請出咱們今天的主角:橋接模式。
將抽象部分與它的實現部分分離,使它們均可以獨立地變化。
抽象部分和實現部分就是兩個不一樣的維度,抽象部分對應上面的消息類型,實現部分對應上面的消息發送方式。如今咱們獨立實現兩個部分,而後消息類型部分想調用消息實現部分去發送消息該怎麼辦呢?很簡單嘛,讓抽象部分持有實現部分的接口,面向接口編程就能夠了,這就是橋接模式名字的由來。橋接抽象部分和實現部分,下面看UML結構圖會更加的清晰。
能夠看到抽象部分的抽象類和實現部分的接口是聚合關係,表示抽象部分持有實現部門的接口,這樣抽象部分就能夠調用實現部分完成功能了。
分析到這裏,你們應該對橋接模式有一個大體的瞭解了吧,下面就來看看如何使用橋接模式來實現上面的消息發送功能。
#import <Foundation/Foundation.h>
#import "messageImplement.h"
@interface abstractMessage : NSObject
@property(strong,nonatomic)id<messageImplement> messageIm;
-(void)send:(NSMutableString*)message;
- (instancetype)initWithImplement:(id<messageImplement>)implement;
@end
====================
#import "abstractMessage.h"
@implementation abstractMessage
- (instancetype)initWithImplement:(id<messageImplement>)implement
{
self = [super init];
if (self) {
self.messageIm = implement;
}
return self;
}
-(void)send:(NSMutableString*)message{
}
@end複製代碼
下面只展現了普通消息的具體類實現,其餘兩種方式相似,詳細見demo
#import "abstractMessage.h"
@interface commonMessage : abstractMessage
@end
====================
#import "commonMessage.h"
@implementation commonMessage
-(void)send:(NSMutableString *)message{
[message insertString:@"【普通消息:" atIndex:0];
[message appendString:@"】"];
[self.messageIm sendMessage:message];
}
@end複製代碼
#import <Foundation/Foundation.h>
@protocol messageImplement <NSObject>
-(void)sendMessage:(NSString *)message;
@end複製代碼
下面只展現使用系統內推送方式發送消息的方式,其餘兩種消息發送方式相似,不在展現,具體見demo
#import <Foundation/Foundation.h>
#import "messageImplement.h"
@interface messageSMS : NSObject<messageImplement>
@end
=================
#import "messageSMS.h"
@implementation messageSMS
-(void)sendMessage:(NSString *)message{
NSLog(@"使用系統內消息方式發送消息,消息內容:%@", message);
}
@end複製代碼
id<messageImplement> messageIMP = [messageMobile new];
abstractMessage *message = [[specialUrgencyMessage alloc]initWithImplement:messageIMP];
NSMutableString *mStr = [[NSMutableString alloc]initWithString:@"大海啊,全是水,駿馬啊,四條腿"];
[message send:mStr];複製代碼
2016-12-15 16:56:43.356 橋接模式[66573:2541266] 使用手機方式發送消息,消息內容:【特別加急消息:大海啊,全是水,駿馬啊,四條腿】複製代碼
你能夠任意組合消息類型和消息發送方式,此時類的數目只有6個,比以前的繼承實現方式9個少了。若是二者都有10種實現方式,那麼使用繼承方式就須要100個類,而使用橋接模式只要20個類,看到了橋接模式的巨大優勢吧。
橋接模式,須要理解橋接二字的由來,看上面的UML圖就明白了,是在抽象和實現之間橋接。由於他們如今分開了,可是抽象部分必須使用實現部分去實現功能,因此抽象部分必須引用實現部分,這就是橋接。
橋接模式對比繼承的有點是把原本混在一塊兒的兩個變化未讀分開,讓他們獨立變化,這樣互相不影響,減小了類的數目,也方便擴展,並且能夠動態替換功能。好比上面的消息發送功能,一樣是發送普通消息,我能夠選擇手機、email其中的任何一種方式,只須要組合起來就好了,比繼承更加靈活。
擴展下去,咱們上面只是兩個維度在變化,那麼若是是三個、四個維度在變化呢?若是你使用繼承去實現,那就完了,不知道要重複寫多少代碼,而使用橋接模式,就能夠把這些變化維度所有獨立分開實現,而後客戶端想怎麼組合就怎麼組合。