设计模式(7) 对象行为型模式 VISTOR 访问者

目录

1. 意图

作用于某对象结构中各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

2. 动机

对于系统中的某些对象,它们存储在同一个集合中,且具有不同的类型,而且对于该集合中的对象,可以接受一类称为访问者的对象来访问,而且不同的访问者其访问方式有所不同,访问者模式为解决这类问题而诞生。

在实际使用时,对同一集合对象的操作并不是唯一的,对相同的元素对象可能存在多种不同的操作方式。而且这些操作方式并不稳定,可能还需要增加新的操作,以满足新的业务需求。

3. 适用性

  • 一个对象结构包含很多类对象,并相对这些对象实施一些依赖于具体类的操作
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,并且避免污染这些对象类
  • 用户对对象类比较熟悉,定义对象结构的类很少改变,但需要经常在结构上定义新操作

4. 结构

5. 参与者

  • Visitor
  • ConcreteVisitor
  • Element
  • ConcreteElement
  • ObjectStructure

6. 协作

7. 效果(优缺点)

优点

  • 增加新的操作——增加新的访问者无须修改原有系统,系统具有较好的可扩展性。
  • 集中存在逻辑相关的操作而剥离无关操作
  • 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作
  • 可以访问不具有相同父类的对象。可以对一个Visitor接口增加任何类型的对象
  • 累积状态——没有访问者,状态需要作为额外的参数传递给进行便利的操作或定义为全局变量

缺点

  • 破坏封装——强迫提供访问元素内部状态的公共操作
  • 增加新的ConcreteElement类很困难——每新增一个ConcreteElement类都要在Visitor中添加一个新的抽象操作

8. 实现

9. 代码示例

课上给的例子

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//雇员类 基类
abstract class Employee{
private string name;
private double income;
private int vacationDays;
public string Name{
get { return name; }
set { name = value; }
}
public double Income{
get { return income; }
set { income = value; }
}
public int VacationDays{
get { return vacationDays; }
set { vacationDays = value; }
}

abstract public void Accept(Visitor visitor);
}
//教师类 子类
class Teacher : Employee{
public Teacher(string name, double income,int vacationDays){
Name = name;
Income = income;
VacationDays = vacationDays;
}
public override void Accept(Visitor visitor){
visitor.Visit(this);
}
}
//工程师类 子类
class Engineer : Employee{
public Engineer(string name, double income,int vacationDays){
Name = name;
Income = income;
VacationDays = vacationDays;
}
public override void Accept(Visitor visitor){
visitor.Visit(this);
}
}
//访问者类
abstract class Visitor{
abstract public void Visit(Employee element);
}
//管理收入的访问者类,管理收入是被集中的具体操作
class IncomeVisitor : Visitor
{
public override void Visit(Employee element){
element.Income *= 1.10;
Console.WriteLine(element.Name + "的新工资是: " + element.Income);
}
}
//管理假期的访问者类,管理假期是被集中的具体操作
class VacationVisitor : Visitor{
public override void Visit(Employee element){
element.VacationDays += 3;
Console.WriteLine(element.Name + "的新假期是" + element.VacationDays);
}
}
//雇员
class Employees{
private ArrayList employees = new ArrayList();
public void Attach(Employee employee){
employees.Add(employee);
}
public void Detach(Employee employee){
employees.Remove(employee);
}
public void Accept(Visitor visitor){
foreach (Employee e in employees)
e.Accept(visitor);
}
}

//使用
static void Main(string[] args){
Teacher zhangsan = new Teacher("张三", 2500.0, 14);
Engineer lisi = new Engineer("李四", 3500.0, 16);
Employees e = new Employees();
e.Attach(zhangsan);
e.Attach(lisi);
IncomeVisitor v1 = new IncomeVisitor();
VacationVisitor v2 = new VacationVisitor();
e.Accept(v1);
e.Accept(v2);
Console.Read();
}

10. 已知应用

实际工业界的例子

静态程序分析,比如检查代码抄袭——用一段程序分析源代码

特点

  • 主要特点是Element的结构树非常复杂,各种代码语法成分、各种语句分类、词法、控制流、数据流,如下图所示

  • 代码分析的需求变化频繁

拓展

存在反面向对象,打破数据+操作

与面向对象思想相反,不同对象之间存在逻辑关系的操作从类中间剥离,并集合在一起

0%