這裏有個OA系統的結構,以下: 設計模式
圖一安全
若是公司發展,在全國開了許多分公司,每一個分公司都有本身的人力、財務、業務等部門。而後每一個分公司下面又設置本身的辦事處,每一個辦事處都也有這些部門,以下:架構
圖二框架
若是讓每一個分公司都用這套系統,根據ID判斷所屬的公司展現對應的部門;問題這樣就不能展現樹狀結構圖,不一樣級別的公司也不能夠簡單的平行管理,並且每個節點都要判斷對應的單位而後調用對應的方法。atom
這裏咱們能夠發現分公司和辦事處和總公司的關係就是部分和總體的關係。spa
總公司的組織架構能夠複用於分公司這其實就是總體與部分能夠被一致對待
的問題設計
若是把公司總部當作一顆大樹的根部,它的下屬分公司其實就是這棵樹的分枝,各個辦事處就是更小的分枝,而相關的職能部門因爲沒有分枝了,它們能夠理解爲葉子。
儘管天下沒有兩片相同的樹葉,可是同一棵樹上長出的葉子也不會差到哪去。也就是說,總部的財務部管理功能也最好複用到子公司,最好的辦法就是它們的財務管理功能的方法都是同樣的。3d
組合模式: 將對象組合成樹行結構以表示‘部分-總體’的層次結構。組合模式使得用戶對單個對象和組合對象的使用具備一致性。code
組合模式將具備相同的基本類型的對象組合成樹形結構的對象,該樹的父節點和子節點具備相同的類型,相同的接口。換句話說,將對象組合成樹形結構以表示「部分-總體」的層次結構,Composite使得用戶對單個對象和組合對象的使用具備一致性。
因爲父節點和子節點具備相同的基本類型,因此在整個樹上不須要作任何類型檢查,客戶端就能夠在父節點和子節點上進行相同的操做,而不須要區分它所須要操做的對象是父節點仍是子節點。使用組合對象的客戶端能夠忽略樹的父節點和字節點得差別,使得用起來很是順手、簡單。對象
上圖二的結構就能夠這樣設計了:
composite: 總公司、分公司、辦事處
leaf: 職能部門
注意:
上述的組合對象是一個樹形結構,不過並不是一個二叉樹,每一個對象都是具備相同的接口,使得客戶端看起來並沒有差別。
靜態結構類圖:
Component所定義的接口是類Leaf和Composite共享的。從上圖的定義來看,顯然有些接口Leaf並無對應的意義,因此在圖中的Leaf中並無看到Component的所有接口,可是,不要覺得Leaf不支持這些接口。雖然有些接口只有在Composite類裏面有意義,好比上述類圖中的add:Component、remove:Component等,可是這不妨礙類Leaf共享該接口,只不過類Leaf實現該方法是使用空方法而已(由於這些接口對Leaf毫無心義,只是爲了和整個樹保持統一而已)。
樹的每一個節點或表示一個葉子節點,或表示一個組合節點,他們的主要區別在於葉子節點沒有組合節點的子節點。可是,由於葉子節點和組合節點共享一套接口,因此任何屬於Component的操做均可以安全地適用於葉子節點和組合節點。
忽略組合對象與單個對象的不一樣,而是可以統一地使用組合結構中的全部對象
但願表現出對象-層次的層次結構
使用組合設計模式:
可使用簡單的基本對象組合成較爲複雜的組合對象,複雜組合對象又能夠組合成更爲複雜的對象,如此遞歸循環。可是使用簡單對象和使用複雜組合對象是無差異的
簡化客戶單代碼,同時使得建立同類型的複雜對象更簡單。由於客戶端不須要區分單個對象仍是組合對象,因此沒必要寫if-else之類的各類判斷
在Cocoa Touch框架中,UIView對象被組合成一個樹形結構,UIView對象能夠包含其餘的UIView對象。這種組合方式便於統一用於事件處理,例如處理渲染事件時,事件會在父視圖中被處理,而後在傳遞給子視圖,由於他們都是相同的類型,事件能夠傳遞到樹形結構的每一視圖。
我們剛開始的問題如今看看如何設計:
具體代碼:
Company類(這是一個抽象類)
/// Abstract class /// 這是一個抽象類 @interface Company : NSObject @property (nonatomic, copy) NSString *name; - (instancetype)initWithName:(NSString *)name; - (void)add:(Company *)company; - (void)remove:(Company *)company; - (void)display; - (void)lineOfDuty; @end @implementation Company - (instancetype)initWithName:(NSString *)name { self = [super init]; if (self) { _name = name; } return self; } - (void)add:(Company *)company { NSAssert(NO, @"子類必須重寫"); } - (void)remove:(Company *)company { NSAssert(NO, @"子類必須重寫"); } - (void)display { NSAssert(NO, @"子類必須重寫"); } - (void)lineOfDuty { NSAssert(NO, @"子類必須重寫"); } @end
ConcreteCompany類
@interface ConcreteCompany () @property (nonatomic, strong) NSMutableArray *children; @end @implementation ConcreteCompany - (instancetype)initWithName:(NSString *)name { self = [super init]; if (self) { self.name = name; _children = [NSMutableArray array]; } return self; } - (void)add:(Company *)company { if (!company) { return; } [self.children addObject:company]; } - (void)remove:(Company *)company { if (!company) { return; } [self.children removeObject:company]; } - (void)display { NSLog(@"---%@:%@ \n", NSStringFromClass([self class]), self.name); for (Company *company in self.children) { [company display]; } } - (void)lineOfDuty { for (Company *company in self.children) { [company lineOfDuty]; } } @end
HRDepartment類
@implementation HRDepartment - (void)add:(Company *)company { } - (void)remove:(Company *)company { } - (void)display { NSLog(@"%@", self.name); } - (void)lineOfDuty { NSLog(@"%@: %@", self.name, @"員工招聘培訓管理"); } @end
FinanceDepartment類
@implementation FinanceDepartment - (void)add:(Company *)company { } - (void)remove:(Company *)company { } - (void)display { NSLog(@"%@", self.name); } - (void)lineOfDuty { NSLog(@"%@: %@", self.name, @"公司財務收支管理"); } @end
Client調用
ConcreteCompany *root = [[ConcreteCompany alloc] initWithName:@"上海總公司"]; [root add:[[HRDepartment alloc] initWithName:@"總公司人力資源部"]]; [root add:[[FinanceDepartment alloc] initWithName:@"總公司財務部"]]; ConcreteCompany *tianjinCompany = [[ConcreteCompany alloc] initWithName:@"天津分公司"]; [tianjinCompany add:[[HRDepartment alloc] initWithName:@"天津分公司人力資源部"]]; [tianjinCompany add:[[FinanceDepartment alloc] initWithName:@"天津分公司財務部"]]; [root add:tianjinCompany]; ConcreteCompany *nanjinAgency = [[ConcreteCompany alloc] initWithName:@"南京辦事處"]; [nanjinAgency add:[[HRDepartment alloc] initWithName:@"南京辦事處人力資源部"]]; [nanjinAgency add:[[FinanceDepartment alloc] initWithName:@"南京辦事處財務部"]]; [tianjinCompany add:nanjinAgency]; ConcreteCompany *wuhanAgency = [[ConcreteCompany alloc] initWithName:@"武漢辦事處"]; [wuhanAgency add:[[HRDepartment alloc] initWithName:@"武漢辦事處人力資源部"]]; [wuhanAgency add:[[FinanceDepartment alloc] initWithName:@"武漢辦事處財務部"]]; [tianjinCompany add:wuhanAgency]; NSLog(@"------------------結構圖\n"); [root display]; NSLog(@"------------------職能\n"); [root lineOfDuty];
輸出結果:
2017-01-17 23:08:48.805 ComponentDemo[10508:507549] ------------------結構圖 2017-01-17 23:08:48.805 ComponentDemo[10508:507549] ---ConcreteCompany:上海總公司 2017-01-17 23:08:48.806 ComponentDemo[10508:507549] 總公司人力資源部 2017-01-17 23:08:48.806 ComponentDemo[10508:507549] 總公司財務部 2017-01-17 23:08:48.806 ComponentDemo[10508:507549] ---ConcreteCompany:天津分公司 2017-01-17 23:08:48.806 ComponentDemo[10508:507549] 天津分公司人力資源部 2017-01-17 23:08:48.806 ComponentDemo[10508:507549] 天津分公司財務部 2017-01-17 23:08:48.806 ComponentDemo[10508:507549] ---ConcreteCompany:南京辦事處 2017-01-17 23:08:48.807 ComponentDemo[10508:507549] 南京辦事處人力資源部 2017-01-17 23:08:48.807 ComponentDemo[10508:507549] 南京辦事處財務部 2017-01-17 23:08:48.807 ComponentDemo[10508:507549] ---ConcreteCompany:武漢辦事處 2017-01-17 23:08:48.807 ComponentDemo[10508:507549] 武漢辦事處人力資源部 2017-01-17 23:08:48.807 ComponentDemo[10508:507549] 武漢辦事處財務部 2017-01-17 23:08:48.808 ComponentDemo[10508:507549] ------------------職能 2017-01-17 23:08:48.808 ComponentDemo[10508:507549] 總公司人力資源部: 員工招聘培訓管理 2017-01-17 23:08:48.821 ComponentDemo[10508:507549] 總公司財務部: 公司財務收支管理 2017-01-17 23:08:48.822 ComponentDemo[10508:507549] 天津分公司人力資源部: 員工招聘培訓管理 2017-01-17 23:08:48.822 ComponentDemo[10508:507549] 天津分公司財務部: 公司財務收支管理 2017-01-17 23:08:48.822 ComponentDemo[10508:507549] 南京辦事處人力資源部: 員工招聘培訓管理 2017-01-17 23:08:48.822 ComponentDemo[10508:507549] 南京辦事處財務部: 公司財務收支管理 2017-01-17 23:08:48.823 ComponentDemo[10508:507549] 武漢辦事處人力資源部: 員工招聘培訓管理 2017-01-17 23:08:48.823 ComponentDemo[10508:507549] 武漢辦事處財務部: 公司財務收支管理