前言
打个比方,家里的水管坏了,我们不会去学习修管道,而是找一个管道工来修理。在软件设计中,如果为了扩展类的功能而往一个类里塞进了太多方法,类就会变得极为复杂。更好的办法是创建外部的类来扩展它。在管道问题的例子中,不会去学习修管道(=向类中添加更多方法),叫来管道工(=访问者),他来了会按门铃,开门让他进来(=接受),然后他进来修管子(=访问),这就是访问者模式。
什么是访问者模式
访问者模式表示一个作用于某对象结构中的各元素的操作,它让我们可以在不改变各元素的类的前提下定义作用域这些元素的新操作。其涉及两个关键角色:访问者和它访问的元素。访问者知道复杂结构中的每个元素,可以访问元素的节点,并根据元素的特征、属性或操作执行任何动作。通过这种方式,元素的执行算法可以随着访问者改变而改变。
访问者模式静态结构的类图.png Visitor
声明了两个 visit*
方法,用于访问和处理各种 Element
类型的对象。ConcreteVisitor
实现这一协议及抽象方法,visit *
的操作定义了针对特定 Element
类型的适当操作,Client
创建 ConcreteVisiotr
,并将其传给一个 Element
对象结构。Element
对象结构中有一个方法接收 Visitor
类型,通过 acceptVisitor
让 Visitor
对象访问发起调用的具体 Element
对象。
什么时候使用访问者模式
- 一个复杂的对象结构包含很多其它对象,它们有不同的接口,但是想对这些对象实施一些依赖于其具体类型的操作
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
访问者模式的优缺点
访问者模式的优点
- 符合单一职责原则。
- 优秀的扩展性
- 灵活性。
访问者模式的缺点
- 具体元素对访问者公布细节,违反了迪米特原则。
- 具体元素变更比较困难。
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
访问者模式的实现
定义一个接受操作的 <ComputerPart> 协议。Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart 接口的实体类。
@class ComputerPartVisitor;
@protocol ComputerPart <NSObject>
- (void)accept:(ComputerPartVisitor *)computerPartVisitor;
@end
我们定义另一个访问者类 ComputerPartVisitor
,它实现了访问者类的操作。
@interface ComputerPartVisitor : NSObject
-(void)visitComputer:(Computer *)computer;
-(void)visitMouse:(Mouse *)mouse;
-(void)visitKeyboard:(Keyboard *)keyboard;
-(void)visitMonitor:(Monitor *)monitor;
@end
@implementation ComputerPartVisitor
- (void)visitMouse:(Mouse *)mouse{
NSLog(@"Mouse");
}
- (void)visitMonitor:(Monitor *)monitor{
NSLog(@"Monitor");
}
- (void)visitKeyboard:(Keyboard *)keyboard{
NSLog(@"Keyboard");
}
- (void)visitComputer:(Computer *)computer{
NSLog(@"Computer");
}
@end
Keyboard、Mouse、Monitor 和 Computer 是实现了 <ComputerPart> 协议的实体类。
@interface Keyboard : NSObject<ComputerPart>
@end
@implementation Keyboard
- (void)accept:(ComputerPartVisitor *)computerPartVisitor{
[computerPartVisitor visitKeyboard:self];
}
@end
@interface Mouse : NSObject<ComputerPart>
@end
@implementation Mouse
- (void)accept:(ComputerPartVisitor *)computerPartVisitor{
[computerPartVisitor visitMouse:self];
}
@end
@interface Monitor : NSObject<ComputerPart>
@end
@implementation Monitor
- (void)accept:(ComputerPartVisitor *)computerPartVisitor{
[computerPartVisitor visitMonitor:self];
}
@end
@interface Computer: NSObject<ComputerPart>
@end
@implementation Computer{
NSArray <id<ComputerPart>> *_parts;
}
- (instancetype)init
{
self = [super init];
if (self) {
_parts = @[[Mouse new],[Keyboard new],[Monitor new]];
}
return self;
}
- (void)accept:(ComputerPartVisitor *)computerPartVisitor{
for (id <ComputerPart> part in _parts) {
[part accept:computerPartVisitor];
[computerPartVisitor visitComputer:self];
}
}
@end
使用 Computer、ComputerPartVisitor 类来演示访问者模式的用法。
Computer *computer = [Computer new];
[computer accept:[ComputerPartVisitor new]];
总结
访问者模式是扩展组合结构功能的一种强有力的方式,主要解决稳定的数据结构和易变的操作耦合问题,通过用各种不同用途的访问者,以同样的方式访问这个稳定的结构,使得结构与其它访问者类中的相关算法分离。
网友评论