结构型设计模式-组合模式

定义

组合模式允许你将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以一致的方式处理单个对象以及对象的组合。

组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进行一致处理的原因。(有点递归的意思)


角色

  • 组合部件(Component):它是一个抽象角色,为要组合的对象提供统一的接口。
  • 叶子(Leaf):在组合中表示子节点对象,叶子节点不能有子节点。
  • 合成部件(Composite):定义有枝节点的行为,用来存储部件,实现在Component接口中的有关操作,如增加(Add)和删除(Remove)。

分类

透明的组合模式、安全的组合模式


场景模拟

设计XML 结构,要求打印每个节点的名字;


组合模式的UML图

组合模式UML图

安全模式代码

#import <Foundation/Foundation.h>

@interface ComponentSafe : NSObject
@property (nonatomic,strong) NSString * name;
- (instancetype)initWithName:(NSString *)name;
-(void)display:(int)level;
@end

#import "ComponentSafe.h"

@implementation ComponentSafe
- (instancetype)initWithName:(NSString *)name
{
    self = [super init];
    if (self) {
        self.name = name;
    }
    return self;
}

@end
#import "ComponentSafe.h"

@interface CompositeSafe : ComponentSafe
-(void)add:(ComponentSafe *)component;
-(void)remove:(ComponentSafe *)component;
@end

#import "CompositeSafe.h"
@interface CompositeSafe()
@property (nonatomic,strong) NSMutableArray *children;

@end
@implementation CompositeSafe
-(instancetype)initWithName:(NSString *)name{
    self= [super initWithName:name];
    if (self) {
        self.children = [NSMutableArray array];
    }
    return self;
}
-(void)add:(ComponentSafe *)component{
    [self.children addObject:component];
}
-(void)remove:(ComponentSafe *)component{
    [self.children removeObject:component];
}
-(void)display:(int)level{
    NSLog(@"- %d %@",level,self.name);
    for (ComponentSafe * component in self.children) {
        [component display:level +2];
    }
}


@end

#import <Foundation/Foundation.h>
#import "ComponentSafe.h"
@interface LeafSafe : ComponentSafe

@end


#import "LeafSafe.h"

@implementation LeafSafe
-(void)display:(int)level{
    NSLog(@"- %d %@",level,self.name);
}
@end

测试代码

  CompositeSafe * root = [[CompositeSafe alloc]initWithName:@"root"];

    [root add:[[LeafSafe alloc]initWithName:@"Leaf A in Root"]];
    [root add:[[LeafSafe alloc]initWithName:@"Leaf B in Root"]];

    
    CompositeSafe * branchX = [[CompositeSafe alloc]initWithName:@"branch x in root"];;
    CompositeSafe * branchY = [[CompositeSafe alloc]initWithName:@"branch y in root"];;

    [root add:branchX];
    [root add:branchY];
    
    [branchX add:[[LeafSafe alloc]initWithName:@"Leaf  in branchA"]];

    CompositeSafe * branchZ = [[CompositeSafe alloc]initWithName:@"branch z in branch X"];;
    [branchX add:branchZ];
    
    [branchY add:[[LeafSafe alloc]initWithName:@"Leaf  in branch Y"]];
    [branchZ add:[[LeafSafe alloc]initWithName:@"Leaf  in branch z"]];

    [root display:1];

测试结果

2018-04-08 18:02:22.958308+0800 结构型设计模式-组合模式[30405:7279512] - 1 root
2018-04-08 18:02:22.958412+0800 结构型设计模式-组合模式[30405:7279512] - 3 Leaf A in Root
2018-04-08 18:02:22.958517+0800 结构型设计模式-组合模式[30405:7279512] - 3 Leaf B in Root
2018-04-08 18:02:22.958680+0800 结构型设计模式-组合模式[30405:7279512] - 3 branch x in root
2018-04-08 18:02:22.958934+0800 结构型设计模式-组合模式[30405:7279512] - 5 Leaf  in branchA
2018-04-08 18:02:22.959220+0800 结构型设计模式-组合模式[30405:7279512] - 5 branch z in branch X
2018-04-08 18:02:22.959381+0800 结构型设计模式-组合模式[30405:7279512] - 7 Leaf  in branch z
2018-04-08 18:02:22.959570+0800 结构型设计模式-组合模式[30405:7279512] - 3 branch y in root
2018-04-08 18:02:22.959792+0800 结构型设计模式-组合模式[30405:7279512] - 5 Leaf  in branch Y

透明模式代码


#import <Foundation/Foundation.h>

@interface Component : NSObject
@property (nonatomic,strong) NSString *name;
-(void)add:(Component *)component;
-(void)remove:(Component *)component;
-(void)display:(int)level;
@end

#import "Component.h"

@implementation Component



@end

#import "Component.h"

@interface Leaf : Component

@end
#import "Leaf.h"

@implementation Leaf
-(void)add:(Component *)component{
    NSLog(@"can not add a component to a leaf.");
}

-(void)remove:(Component *)component{
    NSLog(@"can not remove a component to a leaf");
}
-(void)display:(int)level{
    NSLog(@"- %d %@",level,self.name);
}
@end
#import "Component.h"

@interface Composite : Component

@end

#import "Composite.h"
@interface Composite()
@property (nonatomic,strong) NSMutableArray *children;
@end
@implementation Composite
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.children = [NSMutableArray array];
    }
    return self;
}
-(void)add:(Component *)component{
    [self.children addObject:component];
}

-(void)remove:(Component *)component{
    [self.children removeObject:component];
}
-(void)display:(int)level{
    NSLog(@"- %d %@",level,self.name);
    for (Component * component in self.children) {
        [component display:level +2];
    }
}
@end

测试代码

 Component * root = [Composite new];
    root.name =@"root";
    Component * a = [Leaf new];
    a.name = @"Leaf in Root";
    [root add:a];
    Component * b = [Leaf new];
    b.name = @"Leaf in Root";
    [root add:b];
    
    Component * branchX = [Composite new];
    branchX.name=@"branch x in root";
    [root add:branchX];
    
    Component * branchY = [Composite new];
    branchY.name=@"branch y in root";
    [root add:branchY];
    
    Component * leafA = [Leaf new];
    leafA.name = @"leaf  in Branch X";
    [branchX add:leafA];
    
    Component * branchZ = [Composite new];
    branchZ.name = @"branch z in Branch X";
    [branchX add:branchZ];
    
    Component * leafY = [Leaf new];
    leafY.name = @"leaf in Branch y";
    [branchY add:leafY];
    
    Component * leafz = [Leaf new];
    leafz.name = @"leaf in Branch z";
    [branchZ add:leafz];
    [root display:1];

测试结果

2018-04-08 18:02:22.957212+0800 结构型设计模式-组合模式[30405:7279512] - 1 root
2018-04-08 18:02:22.957364+0800 结构型设计模式-组合模式[30405:7279512] - 3 Leaf in Root
2018-04-08 18:02:22.957458+0800 结构型设计模式-组合模式[30405:7279512] - 3 Leaf in Root
2018-04-08 18:02:22.957554+0800 结构型设计模式-组合模式[30405:7279512] - 3 branch x in root
2018-04-08 18:02:22.957659+0800 结构型设计模式-组合模式[30405:7279512] - 5 leaf  in Branch X
2018-04-08 18:02:22.957873+0800 结构型设计模式-组合模式[30405:7279512] - 5 branch z in Branch X
2018-04-08 18:02:22.957955+0800 结构型设计模式-组合模式[30405:7279512] - 7 leaf in Branch z
2018-04-08 18:02:22.958030+0800 结构型设计模式-组合模式[30405:7279512] - 3 branch y in root
2018-04-08 18:02:22.958141+0800 结构型设计模式-组合模式[30405:7279512] - 5 leaf in Branch y

透明组合模式和安全组合模式区别就是叶子是否有add:和remove方法。有就是透明组合,没有就是安全组合,(因为叶子调用add:和remove:在编译阶段就报错了)


优缺点

优点

  • 组合模式使得客户端代码可以一致地处理对象和对象容器,无需关心处理的是单个对象,还是组合的对象容器。
  • 将”客户代码与复杂的对象容器结构“解耦。
  • 可以更容易地往组合对象中加入新的构件。

缺点

  • 使得设计更加复杂。客户端需要花更多时间理清类之间
    的层次关系。

注意问题

  • 有时候系统需要遍历一个树枝结构的子构件很多次,这时候可以考虑把遍历子构件的结构存储在父构件里面作为缓存。
  • 客户端尽量不要直接调用树叶类中的方法(在我上面实现就是这样的,创建的是一个树枝的具体对象;),而是借用其父类(Graphics)的多态性完成调用,这样可以增加代码的复用性。

《设计模式》一书中提倡:相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。(因为这样可以使用基类处理,符合依赖倒置原则,有更好的扩展性)

借鉴博客

源代码地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容