Objective-C 设计模式-装饰模式(Decorator)

装饰模式定义

  装饰模式(Decorator),动态地为一个对象添加额外的职责,是继承的替代方案,属于结构型模式。通过装饰模式扩展对象的功能比继承子类方式更灵活,使用继承子类的方式,是在编译时静态决定的,即编译时绑定,而且所有的子类都会继承相同的行为。然而,如果使用组合的方式扩展对象的行为,就可以在运行时动态地进行扩展,将来如果需要也可以动态的撤销,而不会影响原类的行为。

 

何时使用装饰模式

  1. 想在不影响其他对象的情况下,以动态、透明的方式为对象添加职责。
  2. 想要扩展对象的行为,但类定义可能被隐藏,无法进行子类化,例如要扩展一个使用单例模式类的行为,就无法通过继承来实现。
  3. 对类的职责是可选的。

 

装饰模式在ios中的实现

  在开发ios应用,有时需要从远程服务器获取数据,如果客户端和服务器通信采用JSON协议来传输数据,在ios中的做法是通过JSON解析器将数据转化为NSDictionary或NSMutableDictionary的字典对象以方便程序使用。但是字典对象提供的存取数据的接口很有限,只有objectForKey:和setObject:forKey:两个方法,当存取Integer、float、BOOL这些数据时,要先将其封装到NSNumber这种包装对象中才能使用,而且字典对象也不会对数据对象进行类型检测。当向setObject:forKey:发送消息时,如果value或key对象为nil系统会抛出NSInvalidArgumentException异常,有时并不希望这种情况出现,要求setObject:forKey:方法能做非空判断并将详细的出错信息输出到后台日志而不影响程序的运行,为了解决这些问题,可以通过装饰模式为字典类的添加额外的职责并增加一些新的功能(这种模式实际是半透明装饰模式,后面会说明)。如下图所示:

 

通过类别实现装饰模式

  以上的实例,如果你是一名ios开发者,你可能立即会想到用类别来实现。没错,用类别实现可以达到同样的效果,而且会更简单。类别是Objective-C的特性,它可以添加类的行为,而不用进行子类化,通过类别添加的方法不会影响类原来的方法,类别也成为类的一部分,并可由其子类继承。

  虽然通过类别可以实现装饰模式,但是这并不是一种严格的实现,由类别添加的方法是编译时绑定的,而装饰模式是动态绑定的,另外类别也没有封装被扩展类的实例。类别适合装饰器不多的时候,上面的例子只有一个NetData装饰器,用类别实现会更轻量,更容易。

 

装饰模式优缺点

优点

  1. 装饰类和被装饰类可以独立扩展,而不会相互耦合。也就是说Component不需要知道是哪个Decorator扩展了它的职责,而Decorator类也不需要知道装饰的是哪个具体的Component。
  2. 装饰模式与继承关系的目的都是要扩展对象的功能但装饰模式比继承方式更为灵活,装饰模式可以动态地扩展一个对象的功能,这些功能可以再动态地撤销,继承关系则不同,继承关系是静态的,它在系统运行前就决定了。
  3. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

缺点

  多层的装饰比较复杂,会产生比继承方式更多的类,更多的类查错起来也比较困难。所以应该尽量减少装饰类的数量,以便降低系统的复杂度。

 

半透明与透明的装饰模式

  装饰模式对客户端的透明性要求程序不要声明一个ConcreteComponent类型的变量,而应当声明一个Component类型的变量,然而,纯粹的装饰模式很难找到。装饰模式的用意是在不改变接口的前提下,增强所考虑的类的性能。在增强性能的时候,往往需要建立新的公开的方法。这就导致了大多数的装饰模式的实现都是“半透明”的,而不是完全透明的。换言之,允许装饰模式改变接口,增加新的方法。这意味着客户端可以声明ConcreteDecorator类型的变量,从而可以调用ConcreteDecorator类中才有的方法。

  半透明的装饰模式是介于装饰模式和适配器模式之间的。适配器模式的用意是改变所考虑的类的接口,也可以通过改写一个或几个方法,或增加新的方法来增强或改变所考虑的类的功能。大多数的装饰模式实际上是半透明的装饰模式,这样的装饰模式也称做半装饰、半适配器模式。

 

装饰模式与适配器模式

  装饰模式和适配器模式都是“包装模式(Wrapper Pattern)”,它们都是通过封装其他对象达到设计的目的的,但是它们的形态有很大区别。

  理想的装饰模式在对被装饰对象进行功能增强的同时,要求具体构件角色、装饰角色的接口与抽象构件角色的接口完全一致。而适配器模式则不然,一般而言,适配器模式并不要求对源对象的功能进行增强,但是会改变源对象的接口,以便和目标接口相符合。

  装饰模式有透明和半透明两种,这两种的区别就在于装饰角色的接口与抽象构件角色的接口是否完全一致。透明的装饰模式也就是理想的装饰模式,要求具体构件角色、装饰角色的接口与抽象构件角色的接口完全一致。相反,如果装饰角色的接口与抽象构件角色接口不一致,也就是说装饰角色的接口比抽象构件角色的接口宽的话,装饰角色实际上已经成了一个适配器角色,这种装饰模式也是可以接受的,称为“半透明”的装饰模式。简单地说,理想的装饰模式是增强了功能但不改变接口;半透明的装饰模式是既增强了功能又改变了接口;而适配器模式是改变接口不增强功能。

  在适配器模式里面,适配器类的接口通常会与目标类的接口重叠,但往往并不完全相同。换言之,适配器类的接口会比被装饰的目标类接口宽。

  显然,半透明的装饰模式实际上就是处于适配器模式与装饰模式之间的灰色地带。如果将装饰模式与适配器模式合并成为一个“包装模式”的话,那么半透明的装饰模式倒可以成为这种合并后的“包装模式”的代表。

 

posted on 2013-06-09 00:18  Markhy  阅读(749)  评论(0编辑  收藏  举报

导航