标签:
何为组合模式?
组合模式让我们可以把相同基类型的对象组合到树状结构中,其中父节点包含同类型的子节点。换句话说,这种树状结构形成"部分——整体"的层次结构。什么是“部分——整体”的层次结构呢?它是既包含对象的组合又包含叶节点的单个对象的一种层次结构。每个组合体包含的其他节点,可以是叶节点或者其他组合体。这种关系在这个层次结构中递归重复。因为每个组合或叶节点有相同的基类型,同样的操作可应用于它们中的每一个,而不必在客户端作类型检查。客户端对组合与叶节点进行操作时可忽略它们之间的差别。
组合模式:将对象组合成树形结构以表示"部分——整体"的层次结构。组合使得用户对单个对象和组合对象的使用的具有一致性。
何时使用组合模式?
@:想获得对象抽象的树形表示(部分——整体层次结构);
@:想让客户端统一处理组合结构中的所有对象。
在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
标签:
原文地址:http://my.oschina.net/daguoshi/blog/504704