?基本概念
組合模式(Composite)拍埠,將對象組合成樹形結(jié)構(gòu)以表示‘部分-整體’的層次結(jié)構(gòu)。組合模式使得用戶對單個對象和組合的對象的使用具有了一致性砚婆。
component為組合中的對象聲明接口械拍,在適當情況下,實現(xiàn)所有類共有接口的默認行為装盯。
leaf在組合中表示葉節(jié)點對象坷虑,葉節(jié)點沒有子節(jié)點。
composite定義有子節(jié)點埂奈,用來存儲字部分迄损,在component接口中實現(xiàn)與字部分有關(guān)的操作。
代碼實現(xiàn)
公司類抽象
@interface Company : NSObject
@property (nonatomic, copy)NSString *name;
@property (nonatomic, strong)NSMutableArray *childrenArray;
- (instancetype)initWithName:(NSString *)name;
- (void)add:(Company *)company;
- (void)remove:(Company *)company;
- (void)display:(int)depth;//顯示
- (void)lineOfDuty;// 履行職責(zé)
#import "Company.h"
@interface Company()
@end
@implementation Company
- (instancetype)initWithName:(NSString *)name
{
self = [super init];
if (self) {
self.name = name;
self.childrenArray = [NSMutableArray array];
}
return self;
}
具體公司類
#import "ConcreteCompany.h"
@implementation ConcreteCompany
- (void)add:(Company *)company
{
[self.childrenArray addObject:company];
}
- (void)remove:(Company *)company
{
if ([self.childrenArray containsObject:company]) {
[self.childrenArray removeObject:company];
}
}
- (void)display:(int)depth
{
NSLog(@"%d-%@",depth,self.name);
for (Company *component in self.childrenArray) {
[component display:(depth + 2)];
}
}
- (void)lineOfDuty
{
for (Company *component in self.childrenArray) {
[component lineOfDuty];
}
}
@end
人力資源部和財務(wù)部
(1)人力
#import "HRDepartment.h"
@implementation HRDepartment
- (void)add:(Company *)company
{
}
- (void)remove:(Company *)company
{
}
- (void)display:(int)depth
{
NSLog(@"%d-%@",depth,self.name);
}
- (void)lineOfDuty
{
NSLog(@"%@ 員工招聘培訓(xùn)管理",self.name);
}
@end
(財務(wù))
#import "FinanceDepartment.h"
@implementation FinanceDepartment
- (void)add:(Company *)company
{
}
- (void)remove:(Company *)company
{
}
- (void)display:(int)depth
{
NSLog(@"%d-%@",depth,self.name);
}
- (void)lineOfDuty
{
NSLog(@"%@ 公司財務(wù)收支管理",self.name);
}
@end
客戶端調(diào)用
ConcreteCompany *root = [[ConcreteCompany alloc] initWithName:@"北京總公司"];
[root add:[[HRDepartment alloc]initWithName:@"總公司人力資源部"]];
[root add:[[FinanceDepartment alloc]initWithName:@"總公司財務(wù)部"]];
ConcreteCompany *comp = [[ConcreteCompany alloc] initWithName:@"上海華東分公司"];
[comp add:[[HRDepartment alloc]initWithName:@"華東分公司人力資源部"]];
[comp add:[[FinanceDepartment alloc]initWithName:@"華東分公司財務(wù)部"]];
[root add:comp];
ConcreteCompany *comp1 = [[ConcreteCompany alloc] initWithName:@"南京辦事處"];
[comp1 add:[[HRDepartment alloc]initWithName:@"南京辦事處人力資源部"]];
[comp1 add:[[FinanceDepartment alloc]initWithName:@"南京辦事處財務(wù)部"]];
[comp add:comp1];
ConcreteCompany *comp2 = [[ConcreteCompany alloc] initWithName:@"杭州辦事處"];
[comp2 add:[[HRDepartment alloc]initWithName:@"杭州辦事處人力資源部"]];
[comp2 add:[[FinanceDepartment alloc]initWithName:@"杭州辦事處財務(wù)部"]];
[comp add:comp2];
[root display:1];
[root lineOfDuty];
輸出
2017-04-28 10:56:51.191 PlayTry[1942:63351] 1-北京總公司
2017-04-28 10:56:51.191 PlayTry[1942:63351] 3-總公司人力資源部
2017-04-28 10:56:51.192 PlayTry[1942:63351] 3-總公司財務(wù)部
2017-04-28 10:56:51.192 PlayTry[1942:63351] 3-上海華東分公司
2017-04-28 10:56:51.192 PlayTry[1942:63351] 5-華東分公司人力資源部
2017-04-28 10:56:51.193 PlayTry[1942:63351] 5-華東分公司財務(wù)部
2017-04-28 10:56:51.193 PlayTry[1942:63351] 5-南京辦事處
2017-04-28 10:56:51.193 PlayTry[1942:63351] 7-南京辦事處人力資源部
2017-04-28 10:56:51.193 PlayTry[1942:63351] 7-南京辦事處財務(wù)部
2017-04-28 10:56:51.194 PlayTry[1942:63351] 5-杭州辦事處
2017-04-28 10:56:51.194 PlayTry[1942:63351] 7-杭州辦事處人力資源部
2017-04-28 10:56:51.194 PlayTry[1942:63351] 7-杭州辦事處財務(wù)部
2017-04-28 10:56:51.195 PlayTry[1942:63351] 總公司人力資源部 員工招聘培訓(xùn)管理
2017-04-28 10:56:51.195 PlayTry[1942:63351] 總公司財務(wù)部 公司財務(wù)收支管理
2017-04-28 10:56:51.196 PlayTry[1942:63351] 華東分公司人力資源部 員工招聘培訓(xùn)管理
2017-04-28 10:56:51.222 PlayTry[1942:63351] 華東分公司財務(wù)部 公司財務(wù)收支管理
2017-04-28 10:56:51.224 PlayTry[1942:63351] 南京辦事處人力資源部 員工招聘培訓(xùn)管理
2017-04-28 10:56:51.224 PlayTry[1942:63351] 南京辦事處財務(wù)部 公司財務(wù)收支管理
2017-04-28 10:56:51.226 PlayTry[1942:63351] 杭州辦事處人力資源部 員工招聘培訓(xùn)管理
2017-04-28 10:56:51.226 PlayTry[1942:63351] 杭州辦事處財務(wù)部 公司財務(wù)收支管理
總結(jié)
將 對 象 組 合 成 樹 形 結(jié) 構(gòu) 以 表 示 “ 部 分 -整 體 ” 的 層 次 結(jié) 構(gòu) 账磺。 組合模式 使 得 用 戶 對 單 個 對 象 和組合對象的使用具有一致性芹敌。
組合模式的目的就是讓客戶端不用區(qū)分操作的對象是子節(jié)點還是葉節(jié)點,而是用一種統(tǒng)一的方式來操作垮抗。
實現(xiàn)這個目標的關(guān)鍵在于氏捞,設(shè)計一個抽象的組件類,讓它可以代碼子節(jié)點和葉節(jié)點冒版,這樣客戶端就不需要區(qū)分二者液茎,統(tǒng)一操作它們即可。
通常辞嗡,組合模式都是用樹形結(jié)構(gòu)來表示的捆等,通過根節(jié)點、子節(jié)點续室、葉節(jié)點組合成一顆對象樹栋烤,這也意味著任何可以使用對象樹來描述或者操作的功能,都可以使用組合模式來進行挺狰,比如XML解析明郭,層次結(jié)構(gòu)的菜單买窟,iOS中由多個子視圖構(gòu)成的復(fù)雜視圖,這些都可以使用組合模式來實現(xiàn)达址。
同時要注意蔑祟,因為要讓客戶端統(tǒng)一操作子節(jié)點和葉節(jié)點趁耗,那么他們的抽象類就必須定義包含二者的所有方法沉唠,如果調(diào)用者調(diào)用了它們不支持的方法,可以拋出異常警告苛败。這雖然違反了單一原則满葛,但是在實際開發(fā)中是合理的。
好處
定義了包含基本對象和組合對象的類層次結(jié)構(gòu)
基本對象可以被組合成更復(fù)雜的組合對
象,而這個組合對象又可以被組合,這樣不斷的遞歸下去罢屈∴秩停客戶代碼中,任何用到基本
對象的地方都可以使用組合對象。
簡化客戶代碼
客戶可以一致地使用組合結(jié)構(gòu)和單個對象缠捌。通常用戶不知道 (也不關(guān)心)處理的是一個葉節(jié)點還是一個組合組件锄贷。這就簡化了客戶代碼 , 因為在定義組合的那些類中不需要寫一些充斥著選擇語句的函數(shù)。
使 得 更 容 易 增 加 新 類 型 的 組 件
新定義的 C o m p o s i t e 或 L e a f 子 類 自 動 地 與 已 有 的 結(jié) 構(gòu) 和 客
戶代碼一起工作,客戶程序不需因新的 C o m p o n e n t類而改變曼月。
使你的設(shè)計變得更加一般化
容易增加新組件也會產(chǎn)生一些問題,那就是很難限制組合
中的組件谊却。有時你希望一個組合只能有某些特定的組件。使用 C o m p o s i t e 時,你不能依賴類型系統(tǒng)施加這些約束,而必須在運行時刻進行檢查哑芹。
使用時機
如果你想表示對象的部分--整體層次結(jié)構(gòu)炎辨。可以選用組合模式把整體和部分統(tǒng)一起來聪姿,使得層次結(jié)構(gòu)實現(xiàn)更簡單碴萧,從外部使用這個層次結(jié)構(gòu)也更容易。
如果你希望統(tǒng)一的使用組合結(jié)構(gòu)中的所有對象末购,這正是組合模式提供的主要功能