標籤:
何為組合模式?
組合模式讓我們可以把相同基底類型的對象組合到樹狀結構中,其中父節點包含同類型的子節點。換句話說,這種樹狀結構形成"部分——整體"的階層。什麼是“部分——整體”的階層呢?它是既包含對象的組合又包含分葉節點的單個對象的一種階層。每個組合體包含的其他節點,可以是分葉節點或者其他組合體。這種關係在這個階層中遞迴重複。因為每個組合或分葉節點有相同的基底類型,同樣的操作可應用於它們中的每一個,而不必在用戶端作類型檢查。用戶端對組合與分葉節點進行操作時可忽略它們之間的差別。
組合模式:將對象組合成樹形結構以表示"部分——整體"的階層。組合使得使用者對單個對象和組合對象的使用的具有一致性。
何時使用組合模式?
@:想獲得對象抽象的樹形表示(部分——整體階層);
@:想讓用戶端統一處理組合結構中的所有對象。
在Cocoa Touch架構中使用組合模式
在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] 公司名稱:視格人力資源部
組合模式的主要意圖是讓樹形結構中的每個節點具有相同的抽象介面。這樣整個結構可作為一個統一的抽象結構使用,而不暴漏其內部表示。對每個節點(分葉節點或組合體)的任何操作,可以通過協議或抽象基類只能怪定義的相同介面來進行。
Demo連結地址:https://github.com/guoshimeihua/Component.git
iOS設計模式——組合模式