装饰器模式(Decorator Pattern)

前言

奋斗好久没更新博客了,尤其是这一系列关于IOS设计模式的文章,之前的几篇的几篇也属于睡睡的那种尴尬。主要原因可能是:1)中间有一个过年阶段 2)前段时间的工作不稳定 3)前段时间玩游戏了。不过主要原因应该是自己懒,给自己找了个不求上进的借口,哎...堕落的人生啊。从现在开始,还是坚持学习,坚持做笔记吧。(好久没写IOS代码了,以致好多代码都不会写了。囧鄙视


定义

先给出比较正式的定义哈。


装饰器一般的理解就是为了实现增强版的对象,而在面向对象的编程中,一般增强一个对象的方法就是:

  • 修改对象的类结构
  • 继承,构造一个继承于目标对象的类,然后再子类里面再把增强的功能加上
显然,上面两种方法都是可以实现增强对象的功能的,但是根据面向对象编程的原则,修改显然是不可取得,至于继承,虽然也可以,但是一般基于增强功能的需求我们一般的做法是 尽量使用对象组合,而不是对象继承 来扩展和复用功能。

装饰器就是基于对象组合的方式实现增强功能的,其本质为动态组合,使用这种方式能够灵活地给对象增加功能,使得能够自由灵活地给对象增加特定的功能,最让人省心的时,一个装饰器不仅仅适用于一个对象的类,而是适用于整个类族,说到类族,那就需要说说装饰器是怎么实现的了。(这个下节再说)

来个装饰器的原理结构图吧,要不然说的模模糊糊,空空虚虚的。



上图中,需要注意的角色是:

  • Component:组件对象的接口,可以给这些对象动态的添加职责,是整个装饰器的祖宗,被装饰的类和装饰器都是继承余这个类的;(当然这也可以是个协议)
  • ConcreteComponent:具体的组件对象,实现了组件接口。该对象通常就是被装饰器装饰的原始对象,可以给这个对象添加职责,我们需要给该类增强功能,拿此对象开刀;
  • Decorator:所有这类装饰器的鼻祖(父类),需要定义一个与组件接口一致的接口;(主要是为了实现装饰器功能的复用,即具体的装饰器A可以装饰另外一个具体的装饰器B,因为装饰器类也是一个Component),并持有一个Component对象,该对象其实就是被装饰的对象。如果不继承组件接口类,则只能为某个组件添加单一的功能,即装饰器对象不能在装饰其他的装饰器对象。(即需要同时满足两个条件)

  • ConcreteDecoratorA和ConcreteDecoratorB:具体的装饰器类,实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象。

从上述原理图我们应该看出:

  1. 装饰器也是和被装饰的对象继承于(如果是协议或者就该说实现)同一个类,因此和抽象父类具备一套一致的接口,如此,装饰器才知道内部如何间接调用被装饰的对象,以及该装饰器能够装饰所有继承于该抽象类的对象。是的,你没说错,装饰器也能够再次被其他装饰器装饰
  2. 由于装饰器和被装饰的对象有共同的祖先,所以他们能够自由地动态组合,一个对象可以被不同的装饰器装饰,一个装饰器也能够装饰不同的对象
  3. 实现的装饰器需要实现父类的公共接口,同时需要包含一个被装饰对象的引用,这样就可以间接调用被装饰对象的接口了

代码示例

Component定义和实现(抽象父类)

#ifndef DecoratorDemo_MyComponent_h
#define DecoratorDemo_MyComponent_h
#import<Foundation/Foundation.h>

@interface MyComponent : NSObject

-(void)ShowName;
-(NSString*)GetName;

@end

#endif

//
//  MyComponent.m
//  DecoratorDemo
//
//  Created by God Lin on 15/4/15.
//  Copyright (c) 2015年 arbboter. All rights reserved.
//

#import "MyComponent.h"

@implementation MyComponent

-(void)ShowName
{
    
}
-(NSString*)GetName
{
    return nil;
}

@end

ConcreteComponent定义和实现(被装饰对象)

//
//  ConcreteMyComponent.h
//  DecoratorDemo
//
//  Created by God Lin on 15/4/15.
//  Copyright (c) 2015年 arbboter. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "MyComponent.h"

@interface ConcreteMyComponent : MyComponent

@end

//
//  ConcreteMyComponent.m
//  DecoratorDemo
//
//  Created by God Lin on 15/4/15.
//  Copyright (c) 2015年 arbboter. All rights reserved.
//

#import "ConcreteMyComponent.h"

@interface ConcreteMyComponent ()

@property (strong, readonly) NSString* name;
@end

@implementation ConcreteMyComponent

-(id)init
{
    self = [super init];
    if(self)
    {
        _name = @"ConcreteMyComponent_name";
    }
    return self;
}

-(void)ShowName
{
    NSLog(@"ConcreteMyComponent::ShowName -> %@", self.name);
}
-(NSString*)GetName
{
    return self.name;
}

@end

Decorator定义和实现(装饰器父类)

//
//  MyDecorator.h
//  DecoratorDemo
//
//  Created by God Lin on 15/4/15.
//  Copyright (c) 2015年 arbboter. All rights reserved.
//
#ifndef DecoratorDemo_MyDecorator_h
#define DecoratorDemo_MyDecorator_h
#import "MyComponent.h"

// 此处因为使用协议,所以没法用父类对象,这里为了偷懒直接使用一个具体对象

@interface MyDecorator : MyComponent

@property (strong, readwrite) MyComponent* component;

-(id)initWithComponent:(MyComponent*)Decoratee;

@end

#endif

//
//  MyDecorator.m
//  DecoratorDemo
//
//  Created by God Lin on 15/4/15.
//  Copyright (c) 2015年 arbboter. All rights reserved.
//

#import "MyDecorator.h"

@implementation MyDecorator

-(id)initWithComponent:(MyComponent *)Decoratee
{
    self = [super init];
    if(self)
    {
        _component = Decoratee;
    }
    return self;
}

-(void)ShowName
{
    // 间接调用
    [self.component ShowName];
}
-(NSString*)GetName
{
    // 间接调用
    return [self.component GetName];
}

@end

具体装饰器的实现

//
//  ConcreteMyDecoratorB.m
//  DecoratorDemo
//
//  Created by God Lin on 15/4/15.
//  Copyright (c) 2015年 arbboter. All rights reserved.
//

#import "ConcreteMyDecoratorB.h"

@implementation ConcreteMyDecoratorB
-(NSString*)ConcreteMyDecoratorBGetInfo
{
    return @"ConcreteMyDecoratorB:GetInfo";
}
@end

//
//  ConcreteMyDecoratorA.m
//  DecoratorDemo
//
//  Created by God Lin on 15/4/15.
//  Copyright (c) 2015年 arbboter. All rights reserved.
//

#import "ConcreteMyDecoratorA.h"

@implementation ConcreteMyDecoratorA
-(void)ConcreteMyDecoratorAOpration
{
    NSLog(@"ConcreteMyDecoratorA::ConcreteMyDecoratorAOpration");
}
@end


客户端调用代码

ConcreteMyComponent* c = [[ConcreteMyComponent alloc] init];
ConcreteMyDecoratorA* da = [[ConcreteMyDecoratorA alloc] initWithComponent:c];
ConcreteMyDecoratorB* db = [[ConcreteMyDecoratorB alloc] initWithComponent:c];

[da ShowName];
NSLog(@"%@",[da GetName]);
[da ConcreteMyDecoratorAOpration];
NSLog(@"%@",[db ConcreteMyDecoratorBGetInfo]); 

上述客户端代码演示了两个装饰器装饰同一个对象,同时通过装饰器在原来的对象上增加了操作的。



总结

通过上面对装饰器的学习,你大概早就发现了这他妈的大概不是和Objective-C里面的分类和扩展类似!!!是的,分类和扩展就是使用装饰器的设计模式增强类对象的功能的。通过动态地组合对象,我们可以使用装饰器不断地增强目标对象,而不需要修改影响原对象,充分体现了面向对象的编程思想和优势。

在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;需要动态地给一个对象增加功能,这些功能也可以动态地被撤销;当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时,这时候我们或许可以考虑这里说的装饰器设计模式了。

下面来总结下装饰器的优缺点,最后的总结((*^__^*) )

优点

  • 装饰者模式可以提供比继承更多的灵活性
  • 可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
  • 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
  • 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合开闭原则


缺点

  •  会产生很多的小对象,增加了系统的复杂性
  • 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。



参考

  1. 设计模式读书笔记-----装饰者模式
  2. 装饰器模式(Decorator)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值