概念:标准的装饰模式有包括一个抽象的Component父类,它声明了一些操作,它具体的类讲进行重载以实现自己特定的操作。这个Component具体类是模式中的被装饰者,Component父类可以被细化为另一个叫做Decorator的抽象类,即装饰者抽象类。Decorator类中包含了一个Component的引用。Decorator的具体类为Component或者Decorator定义了几个扩展行为,并且会在自己的操作中内嵌Component操作。关系图见 装饰模式类图
Component定义了一些抽象操作,具体类将进行重载实现自己特定的操作。Decorator抽象类通过将一个Component(或Decorator)内嵌到Decorator对象,定义了扩展这个Component的实例的“装饰性”的行为。默认的operation方法只是想内嵌的Component发送一个消息,Decorator的具体实现类重载父类的operation,通过super把自己增加的行为扩展给Component的operation。如果只需要向Component添加一种职责,那可以省掉抽象的Decorator类,让具体的Decorator直接把请求转发给Component。那么这种方式就好像形成一种操作链,把一种行为加到另一种行为之上。
2.装饰者模式概念图
装饰者模式类图
装饰模式使用场景
想要在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。想要扩展一个类的行为,却做不到。类定义可能被隐藏,无法进行子类化;或者对类的每个行为的扩展,为支持每种功能组合,将产生大量的子类,对类的职责的扩展是可选的。
1.当系统需要新功能时,向旧类中添加新的代码,这些新代码只是装饰了原有类的核心职责,并没有替换掉原有类的核心职责。新的字段、方法和逻辑增加了原有类的复杂度。这些新加入的东西仅仅是为了满足一些只在某种特定情况下才执行的特殊需要,不必加入原有类,增加复杂度。
2.装饰者模式提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类当中,并让这个类包装它所要装饰的对象。当需要执行特殊行为时,viewController 中的代码就可以在运行时根据需要有选择、按顺序地使用装饰对象了。
3.装饰模式可以把类中的装饰功能去除,简化类,有效区分核心职责和装饰功能,去除相关类中重复的装饰逻辑。
使用案例:
一个女孩需要出席一场晚会,这个时候需要盛装打扮下自己。使用装饰者模式就再好不过了。
首先定义一个类,这个类是要出席晚会的girl,被装饰对象。
实现代码细节
@interfaceGirl:NSObject代表名字@property(nonatomic,strong)NSString*name;//穿的装饰品- (void)show;@end
//展示自己穿了什么衣服- (void)show{NSLog(@"%@",self.name); }- (void)setName:(NSString*)name{ _name = name;}
在定义一个装饰类Finery 类 其实就是 Decorator 类(装饰抽象类)
#import"Girl.h"@classGirl;@interfaceFinery : Girl;@property(nonatomic,strong)Girl*component;@end
#import"Finery.h"@implementationFinery- (void)show{if(self.component!=nil) { [self.component show]; }}- (void)setComponent:(Girl *)component{ _component = component;}@end
然后就可以定义具体的类,比如衣服,鞋子,裤子。去扩展装饰对象,修饰装饰对象。
#import"Finery.h"@interfaceShoes:Finery@end
#import"Shoes.h"@implementationShoes- (void)show{ [supershow];NSLog(@"鞋子");}@end
具体调用方式
- (void)viewDidLoad { [superviewDidLoad]; self.navigationController.title = @"装饰者模式"; Girl *girl = [[Girl alloc] init]; girl.name = @"james"; Shoes *shoe = [Shoesnew]; shoe.component = girl; [shoe show];}
实现结果
效果图
分析实现过程:
Finery 不会被直接使用,而是作为具体装饰类的父类存在。具体服饰类,就是Shoes 这些类,这些类需要在调用父类 show 方法的同时实现自己特有的方法。首先,创建的girl对象给name赋值为james,然后创建shoe对象,设置shoe的component = girl,然后调用[shoe show];来到show方法内部 执行 NSLog(@"鞋子");
[super show];会来到父类也就是装饰类Finery中调用
- (void)show{if(self.component!=nil) { [self.component show]; }}
由于self.component是Girl类型,所以会执行Girl内部的show方法输出James.