iOS设计模式-装饰者模式

一、定义

装饰者模式动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

装饰者模式采用了多用组合,少用继承对扩展开放,对修改关闭的OO原则。一个组件可以被无数个装饰者包装。

二、使用场景

  1. 需要扩展一个类的功能,或给一个类添加附加职责。
  2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。
  4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类。使得子类数目呈爆炸式增长。另一种可能是因为类定义被隐藏,或类定义不能用户生成子类。

三、具体实现

购买咖啡时,会根据要求加入各种调料,例如:牛奶、豆浆、摩卡等等,我们需要根据加入的不同调料收取不同的费用。下面我们使用装饰者模式来实现点单系统,返回正确的价格。

首先我们先确定咖啡是被装饰者,调料是装饰者,一个咖啡理论上可以添加无数的调料。

  1. 创建咖啡协议,所有的咖啡都有名称和价格属性。

     // Baverage.h
     @protocol Baverage 
    
     @required
    
     - (NSString *)name;
    
     - (double)cost;
    
     @end
    
  2. 创建调料协议,装饰者和被装饰者必须是一样的类型,也就是需要有共同的超类(咖啡和调料的共同超类是NSObject,分别实现不同的协议)

     // Condiment.h
     @protocol Condiment 
    
     - (instancetype)initWithBaverage:(id)baverage;
    
     @end
    
  3. 实现具体的咖啡对象,分别实现咖啡协议

     // Espresso.m
     @implementation Espresso
    
     - (NSString *)name {
         return @"Espresso";
     }
    
     - (double)cost {
         return 1.99;
     }
    
     @end
     
     // HouseBlend.m
     @implementation HouseBlend
    
     - (NSString *)name {
         return @"HouseBlend";
     }
     
     - (double)cost {
         return 0.9;
     }
    
     @end
    
  4. 实现具体的调料对象,实现调料协议.需要引用一个咖啡实例。

     // Moca.m
     @implementation Moca
     
     - (instancetype)initWithBaverage:(id)baverage
     {
         if (self = [super init]) {
             _baverage = baverage;
         }
         
         return self;
     }
     
     - (NSString *)name {
         return [NSString stringWithFormat:@"%@, Moca", [self.baverage name]];
     }
     
     - (double)cost {
         return 0.3 + [self.baverage cost];
     }
    
     @end
     
     // Milk.m
     @implementation Milk
    
     - (instancetype)initWithBaverage:(id)baverage
     {
         if (self = [super init]) {
             _baverage = baverage;
         }
         
         return self;
     }
     
     - (NSString *)name {
         return [NSString stringWithFormat:@"%@, Milk", [self.baverage name]];
     }
     
     - (double)cost {
         return 0.1 + [self.baverage cost];
     }
     
     @end
    
  5. 开始点咖啡

     // 来一杯添加摩卡、牛奶、豆浆的浓缩咖啡
     id baverage = [[Espresso alloc] init];
     baverage = [[Moca alloc] initWithBaverage:baverage];
     baverage = [[Milk alloc] initWithBaverage:baverage];
     baverage = [[Soy alloc] initWithBaverage:baverage];
     NSLog(@"%@ --- %lf",[baverage name], [baverage cost]);
     
     // 一杯加双倍摩卡的黑咖啡
     id houseBlend = [[HouseBlend alloc] init];
     houseBlend = [[Moca alloc] initWithBaverage:houseBlend];
     houseBlend = [[Moca alloc] initWithBaverage:houseBlend];
     NSLog(@"%@ --- %lf",[houseBlend name], [houseBlend cost]);
    

其实装饰模式在使用的时候,和程序中的递归操作很类似,逐级查询价格,逐级返回,最终得到一个总的价格。

四、总结

优点
  1. 装饰者模式与继承关系的目的都是要扩展对象的功能,但是装饰者模式可以提供比继承更多的灵活性。
  2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
缺点
  1. 会在设计中加入大量的小类,如果过度使用,会让程序变得复杂。
  2. 增加代码的复杂度
  3. 需要相同的超类,否则会出现类型不匹配的问题。

Demo地址

你可能感兴趣的:(iOS设计模式-装饰者模式)