定义:
提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。访问者模式使得用户可以在不修改现有系统的情况下扩展系统的功能,为这些不同类型的元素增加新的操作。
实例:
在使用访问者模式时,被访问元素通常不是单独存在的,它们存储在一个集合中,这个集合被称为「对象结构」,访问者通过遍历对象结构实现对其中存储的元素的逐个操作。通过一个简单的例子了解访问者模式,访问者有财务部门FADepartment
和 HR 部门HRDepartment
,通过访问雇员Employee
来查看雇员的工作情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| @interface Department : NSObject
- (void)visitEmployee:(Employee *)employee;
@end
@implementation Department
- (void)visitEmployee:(Employee *)employee {}
@end
@interface FADepartment : Department @end
@implementation FADepartment
- (void)visitEmployee:(Employee *)employee { if (employee.workTime > 40) { NSLog(@"%@ 工作时间满 40 小时", employee.name); }else{ NSLog(@"%@ 工作时间不满 40 小时,要警告!", employee.name); } }
@end
@interface HRDepartment : Department @end
@implementation HRDepartment
- (void)visitEmployee:(Employee *)employee { NSUInteger weekSalary = employee.workTime * employee.salary; NSLog(@"%@ 本周获取薪资:%ld",employee.name , weekSalary); }
@end
@interface Employee : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSUInteger workTime;
@property (nonatomic, assign) NSUInteger salary;
- (void)accept:(Department *)department;
@end
@implementation Employee
- (void)accept:(Department *)department {}
@end
@interface FulltimeEmployee : Employee
@end
@implementation FulltimeEmployee
- (void)accept:(Department *)department { [department visitEmployee:self]; }
@end
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| FADepartment *fa = [FADepartment new]; HRDepartment *hr = [HRDepartment new];
FulltimeEmployee *tim = [FulltimeEmployee new]; tim.name = @"tim"; tim.workTime = 55; tim.salary = 100;
FulltimeEmployee *bill = [FulltimeEmployee new]; bill.name = @"bill"; bill.workTime = 38; bill.salary = 150;
NSArray *employeeList = @[tim, bill]; [employeeList enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { Employee *employee = obj; [employee accept:fa]; [employee accept:hr]; }];
输出: tim 工作时间满 40 小时 tim 本周获取薪资:5500 bill 工作时间不满 40 小时,要警告! bill 本周获取薪资:5700
|
优点:
- 增加新的访问操作很方便。使用访问者模式,增加新的访问操作就意味着增加一个新的具体访问者类,实现简单,无须修改源代码,符合“开闭原则”。
- 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问。
- 让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作。
缺点:
- 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”的要求。
- 破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问。