何爲組合模式?git
組合模式讓咱們能夠把相同基類型的對象組合到樹狀結構中,其中父節點包含同類型的子節點。換句話說,這種樹狀結構造成"部分——總體"的層次結構。什麼是「部分——總體」的層次結構呢?它是既包含對象的組合又包含葉節點的單個對象的一種層次結構。每一個組合體包含的其餘節點,能夠是葉節點或者其餘組合體。這種關係在這個層次結構中遞歸重複。由於每一個組合或葉節點有相同的基類型,一樣的操做可應用於它們中的每個,而沒必要在客戶端做類型檢查。客戶端對組合與葉節點進行操做時可忽略它們之間的差異。github
組合模式:將對象組合成樹形結構以表示"部分——總體"的層次結構。組合使得用戶對單個對象和組合對象的使用的具備一致性。框架
什麼時候使用組合模式?atom
@:想得到對象抽象的樹形表示(部分——總體層次結構);spa
@:想讓客戶端統一處理組合結構中的全部對象。code
在Cocoa Touch框架中使用組合模式component
在Cocoa Touch框架中,UIView被組織成一個組合結構。每一個UIView的實例能夠包含UIView的其餘實例,造成統一的樹形結構。讓客戶端對單個UIView對象和UIView的組合統一對待。對象
窗口中的UIView在內部造成它的子視圖。它們的每個能夠包含其餘視圖而變成本身的子視圖的超視圖。添加進來的其餘UIView成爲它的子視圖。它們的每個能夠包含其餘視圖而變成本身的子視圖的超視圖。UIView對象只能有一個超視圖,能夠有零到多個子視圖。遞歸
視圖組合結構參與繪圖事件處理。當請求超視圖爲顯示進行渲染時,消息會先在超視圖被處理,而後傳給其子視圖。消息會傳播到遍佈整個樹的其餘子視圖。由於它們是相同的類型——UIView,它們能夠被統一處理。接口
組合模式的實例引用
先看下組合模式的靜態結構如圖:
基接口是定義了CompanyLeaf類和CompanyComponent類的共同操做的CompanyProtocol。有些操做支隊Component有意義,好比addCompany、removeCompany。爲什不不把這些方法放在CompanyComponent類中呢?由於咱們不想讓客戶端在運行時知道它們在處理哪一種類型的節點,也不想把組合結構的內部細節暴漏給客戶端。這就是爲何雖然操做只對CompanyComponent有意義,咱們仍是把它們聲明在基接口,使得各種節點具備相同的接口,這樣就可讓客戶端對它們統一處理。
共同操做CompanyProtocol的代碼以下:
#import <Foundation/Foundation.h> @protocol CompanyProtocol <NSObject> - (void)addCompany:(id<CompanyProtocol>)company; - (void)removeCompany:(id<CompanyProtocol>)company; - (void)display; //展現總公司以及子公司 @end
共同的操做定義了添加公司、刪除公司、展現公司三個方法,咱們接着看下組合CompanyComponent類是怎麼實現的,代碼以下:
#import <Foundation/Foundation.h> #import "CompanyProtocol.h" @interface CompanyComponent : NSObject <CompanyProtocol> @property (nonatomic, copy) NSString *companyName; - (instancetype)initWithCompanyName:(NSString *)companyName; @end
#import "CompanyComponent.h" @interface CompanyComponent () @property (nonatomic, strong) NSMutableArray *childList; @end @implementation CompanyComponent - (instancetype)initWithCompanyName:(NSString *)companyName { self = [super init]; if (self) { _companyName = companyName; _childList = [[NSMutableArray alloc] initWithCapacity:0]; } return self; } - (void)addCompany:(id<CompanyProtocol>)company { [self.childList addObject:company]; } - (void)removeCompany:(id<CompanyProtocol>)company { [self.childList removeObject:company]; } - (void)display { NSLog(@"公司名稱:%@", self.companyName); for (id<CompanyProtocol> company in self.childList) { [company display]; } } @end
CompanyLeaf的代碼以下:
#import <Foundation/Foundation.h> #import "CompanyProtocol.h" @interface CompanyLeaf : NSObject <CompanyProtocol> @property (nonatomic, copy) NSString *companyName; - (instancetype)initWithCompanyName:(NSString *)companyName; @end
#import "CompanyLeaf.h" @implementation CompanyLeaf - (instancetype)initWithCompanyName:(NSString *)companyName { self = [super init]; if (self) { _companyName = companyName; } return self; } - (void)addCompany:(id<CompanyProtocol>)company { // 子節點雖然也實現這些方法,可是不作任何的處理,這樣就方便客戶端進行調用,省去判斷類型的步驟。 // 這個方法子節點不具有 } - (void)removeCompany:(id<CompanyProtocol>)company { // 子節點雖然也實現這些方法,可是不作任何的處理,這樣就方便客戶端進行調用,省去判斷類型的步驟。 // 這個方法子節點不具有 } - (void)display { NSLog(@"公司名稱:%@", self.companyName); } @end
從代碼中咱們能夠看到雖然在CompanyLeaf中有addCompany,可是卻沒有作任何處理,說明CompanyLeaf類不實現這個方法,這樣寫的好處就是保持了接口的一致性,這樣客戶端不用去區分組合類型與葉子類型。
客戶端代碼的調用以下:
#import "ViewController.h" #import "CompanyProtocol.h" #import "CompanyComponent.h" #import "CompanyLeaf.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; CompanyComponent *root = [[CompanyComponent alloc] initWithCompanyName:@"嘟嘟牛科技有限公司"]; // 添加一個葉子節點 [root addCompany:[[CompanyLeaf alloc] initWithCompanyName:@"嘟嘟牛人力資源部"]]; CompanyComponent *component = [[CompanyComponent alloc] initWithCompanyName:@"深圳視格有限公司(嘟嘟牛子公司)"]; [component addCompany:[[CompanyLeaf alloc] initWithCompanyName:@"視格人力資源部"]]; // 添加一個組合節點 [root addCompany:component]; NSLog(@"-----------------結構圖----------------"); [root display]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
輸出以下:
2015-09-10 22:22:27.493 Component[27847:655455] -----------------結構圖---------------- 2015-09-10 22:22:27.494 Component[27847:655455] 公司名稱:嘟嘟牛科技有限公司 2015-09-10 22:22:27.494 Component[27847:655455] 公司名稱:嘟嘟牛人力資源部 2015-09-10 22:22:27.494 Component[27847:655455] 公司名稱:深圳視格有限公司(嘟嘟牛子公司) 2015-09-10 22:22:27.495 Component[27847:655455] 公司名稱:視格人力資源部
組合模式的主要意圖是讓樹形結構中的每一個節點具備相同的抽象接口。這樣整個結構可做爲一個統一的抽象結構使用,而不暴漏其內部表示。對每一個節點(葉節點或組合體)的任何操做,能夠經過協議或抽象基類只能怪定義的相同接口來進行。