解释器模式
# 分类
行为型模式
# 定义
- 解释器模式(Interpreter Pattern))给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
# 意图
- 访问者模式的意图是表示一个作用于某对象结构中各元素的操作,它使你可以在不改变各元素类的提前下定义作用于这些元素的新操作。
- 访问者模式的目的是把处理或者说是操作从数据结构中分离出来。
# 应用场景
- 如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
# 角色与结构图
- 抽象表达式角色:声明一个抽象的解释操作,这个接口为所有具体表达式角色都要实现的。
- 终结符表达式角色:具体表达式。
- 非终结符表达式角色:具体表达式。
- 上下文(环境)角色:包含解释器之外的一些全局信息。
- 客户角色
下图解释了解释器模式中各角色的作用

# 示例代码
//访问者抽象类,按照数据元素定义固定个数的行为
abstract class Visitor
{
public abstract void Visit(ConcreteElementA concreteElementA);
public abstract void Visit(ConcreteElementB concreteElementB);
}
//访问者1,实现所有接口
class ConscreteVisitor1 : Visitor
{
public override void Visit(ConcreteElementA concreteElementA){
Console.WriteLine("{0}被{1}访问",concreteElementA.GetType(),this.GetType().Name);
}
public override void Visit(ConcreteElementB concreteElementB){
Console.WriteLine("{0}被{1}访问",concreteElementB.GetType(),this.GetType().Name);
}
}
//访问者2,实现所有接口
class ConscreteVisitor2 : Visitor
{
public override void Visit(ConcreteElementA concreteElementA){
Console.WriteLine("{0}被{1}访问",concreteElementA.GetType(),this.GetType().Name);
}
public override void Visit(ConcreteElementB concreteElementB){
Console.WriteLine("{0}被{1}访问",concreteElementB.GetType(),this.GetType().Name);
}
}
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
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
//定义数据结构抽象类
abstract class Element {
public abstract void Accept(Visitor visitor);
}
class ConcreteElementA : Element{
public override void Accept(Visitor visitor){
visitor.Visit(this);
}
public void OperationA(){
其他操作A......
}
}
class ConcreteElementB : Element{
public override void Accept(Visitor visitor){
visitor.Visit(this);
}
public void OperationB(){
其他操作B......
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素
class ObjectStructure{
private IList<Element> elements = new List<Element>();
public void Attach(Element element){
elements.Add(element);
}
public void Dettach(Element element){
elements.Remove(element);
}
public void Accept(Visitor visitor){
foreach(Element element in elements){
e.Accept(visitor);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//客户端
static void main(String[] args) {
ObjectStructure object = new ObjectStructure();
object.Attach(new ConcreteElementA());
object.Attach(new ConcreteElementB());
ConcreteVisitor1 v1 = new ConcreteVisitor1();
ConcreteVisitor1 v2 = new ConcreteVisitor2();
object.Accept(v1);
object.Accept(v2);
Console.ReadLine();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 优点
- 增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。
- 访问者模式将有关的行为集中到一个访问者对象中。
- 具体元素类负责数据加载,具体访问者负责行为实施,两个不同的职责非常明确的分离开来,各自演绎而变化,其次由于职责分开,继续增加对数据的操作会非常快捷。
- 把数据仍给访问者,由访问者来执行内部功能。
# 缺点
- 访问者要访问一个类就必然要求这个类公布一些方法和属性,也就是说访问者关注了其他类的内部细节,这既破坏了类的封装性,也是迪米特法则所不建议的。
- 在访问者模式中,元素与访问者之间能够传递的信息有限,这往往也会限制访问者模式的使用。(访问者想要元素的数据或方法,元素就不得不公开给访问者,即使真正没必要)
- 具体角色的增减修改会是比较苦难的。
# 小结
- 解释器模式描述了如何构成一个简单的语言解释器,主要应用在使用面向对象语言开发编译器中;在实际应用中,我们可能很少碰到去构造一个语言的文法的情况。
# 一句话概括
给定一个语言,定义它的文法的一种表示,并定义一个解释器。
编辑 (opens new window)
上次更新: 2025/03/22, 13:47:44