这里有个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] 武汉办事处财务部: 公司财务收支管理