装饰模式(Decorator Pattern) 也称为包装模式,结构型设计模式之一。 其使用一种对客户端透明的方式来动态地扩展对象功能,同时它也是继承关系的一种替代方案。
定义装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
扩展扩展是一种十分强大的机制,可以让你在不用继承的情况下,给已存在的类、结构体或者枚举类添加一些新的功能。最重要的一点是,你可以在你没有访问权限的情况下扩展已有类。这意味着你甚至可以扩展 Cocoa 的类,比如 UIView 或者 UIImage 。
举个例子,在编译时新加的方法可以像扩展类的正常方法一样执行。这和装饰器模式有点不同,因为扩展不会持有扩展类的对象。
使用场景-
需要扩展一个类的功能,或给一个类添加附加职责。
-
需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
-
需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使用继承关系实现不现实。
-
当不能采用生成子类的方法进行扩充时。比如类定义被隐藏或类定义无法被继承。
-
Component:抽象组件,给出一个抽象接口,以规范准备接收附加能力的对象。
-
ConcreteComponent: 具体组件,定义一个将要接收附加能力的类,即被装饰的具体对象。
-
Decorator: 抽象装饰者,其职责就是装饰我们的组件,其内部会有一个指向组件对象的引用
-
ConcreteDecoratorA, ConcreteDecoratorB: 装饰者的具体实现类,用于附加上不同的能力
extension Double{
var km : Double { return self * 1000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1000.0 }
var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm;
print("One inch is \(oneInch)meters")
objective-c
例子1
//MyClass.h
@interface MyClass : NSObject
- (float)value;
@end
//MyClass.m
@interface MyClass () { //注意此处:扩展
float value;
}
- (void)setValue:(float)newValue;
@end
@implementation MyClass
- (float)value {
return value;
}
- (void)setValue:(float)newValue {
value = newValue;
}
@end
例子2
//Person_extension.h
#import "Person.h"
@interface Person () {
NSString *_someStr;
}
@property NSObject *extraProperty;
@property (readwrite) NSString *uniqueIdentifier;
@end
委托
装饰者模式的另一种实现方案是委托。在这种机制下,一个对象可以和另一个对象相关联。比如你在用UITableView
,你必须实现tableView(_:numberOfRowsInSection:)
这个委托方法。 你不应该指望UITableView
知道你有多少数据,这是个应用层该解决的问题。所以,数据相关的计算应该通过UITableView
的委托来解决。这样可以让UITableView
和数据层分别独立。视图层就负责显示数据,你递过来什么我就显示什么。
下面这张图很好的解释了UITableView
的工作过程:
UITableView
的工作仅仅是展示数据,但是最终它需要知道自己要展示那些数据,这时就可以向它的委托询问。在 objc 的委托模式里,一个类可以通过协议来声明可选或者必须的方法。
看起来似乎继承然后重写必须的方法来的更简单一点。但是考虑一下这个问题:继承的结果必定是一个独立的类,如果你想让某个对象成为多个对象的委托,那么子类这招就行不通了。
注意:委托模式十分重要,苹果在 UIKit 中大量使用了该模式,基本上随处可见。
如何使用委托模式 swift例子1
protocol FullyNamed {
var fullName: String { get }
}
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName 为 "John Appleseed"
例子2
//定义一个协议
protocol LogManagerDelegate {
func writeLog()
}
//用户登录类
class UserController {
var delegate : LogManagerDelegate?
func login() {
//查看是否有委托,然后调用它
delegate?.writeLog()
}
}
//日志管理类
class SqliteLogManager : LogManagerDelegate {
func writeLog() {
print("将日志记录到sqlite数据库中")
}
}
//使用
let userController = UserController()
userController.login() //不做任何事
let sqliteLogManager = SqliteLogManager()
userController.delegate = sqliteLogManager
userController.login() //输出“将日志记录到sqlite数据库中”
Objective - C
//Mydelegate.h
//可以单独放在一个.h文件,也可以直接放入A.h中
@protocol Mydelegate//协议的声明 中
-(void)Fun;
@end
//A.h
#import "Mydelegate.h"
@interface A:NSObject
{
id delegate;//声明一个委托对象,我们要把事情委托给实现Mydelegate协议的类
}
@property(assign,nonatomic) id delegate;
@end
//A.m
#import "A.h"
@implementation
-(void)FunToOther
{
[delegate Fun];//将消息发送给委托去处理
}
@end
//B.h
#import"A.h"
@interface B:NSObject
@property(strong,nonatomic) A *a;
@end
//B.m
#import "B.h"
@implementation
-(void)init
{
_a = [[A alloc] init];
_a.delegate = self;
}
#prage mark - MyDelegate
-(void)fun
{
//实现Mydelegate中制定的方法
}
@end
有需要文中完整代码的同学: 现在私信发送 “底层源码” 即可免费获取
现在私信还可以获取《更多 Android 源码解析+学习大纲+面试真题》
装饰者模式的性能非常好, 在项目中,你会有非常多的因素考虑不到,特别是业务的变更,不时地冒出一个需求,装饰模式可以给我们很好的帮助,通过装饰模式重新封装一 个类,而不是通过继承来完成, 对原有程序没有变更。
缺点可忽略,还是那句话,类增加了,麻烦。可以在实际需要时再抽象组件,避免过度设计
最后我想说:
对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们
技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面
Android 架构师之路还很漫长,与君共勉