结构图
角色
- 抽象表达式(AbstractExpression)角色:声明一个执行操作的接口。
- 终结符表达式(TerminalExpression)角色:。实现抽象表达式接口。此处为一般语句。
- 非终结符表达式(NonterminalExpression)角色:实现抽象表达式接口。此处为循环语句。
- 环境(Context)角色:提供解析器之外的一些全局信息。
动机
在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现。如果使用普通的编程方式来实现将面临非常频繁的变化。在这种情况下,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。
意图
给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。
示意性代码
示意性代码
'MainApp test application
Public Class MainAppClass MainApp
Public Sub Main()Sub Main()
Dim context As New Context
'Usually a tree
Dim list As New List(Of AbstractExpression)
'Populate 'abstract syntax tree'
list.Add(New TerminalExpression())
list.Add(New NonterminalExpression())
list.Add(New TerminalExpression())
list.Add(New TerminalExpression())
'Interpret
For Each exp As AbstractExpression In list
exp.Interpret(context)
Next
'Wait for user
Console.ReadLine()
End Sub
End Class
'"Context"
Public Class ContextClass Context
End Class
'"AbstractExpression"
Public MustInherit Class AbstractExpressionClass AbstractExpression
Public MustOverride Sub Interpret()Sub Interpret(ByVal context As Context)
End Class
'"TerminalExpression"
Public Class TerminalExpressionClass TerminalExpression
Inherits AbstractExpression
Public Overrides Sub Interpret()Sub Interpret(ByVal context As Context)
Console.WriteLine("Called TerminalExpression.Interpret")
End Sub
End Class
'"NonterminalExpression"
Public Class NonterminalExpressionClass NonterminalExpression
Inherits AbstractExpression
Public Overrides Sub Interpret()Sub Interpret(ByVal context As Context)
Console.WriteLine("Called NonterminalExpression.Interpret")
End Sub
End Class
'MainApp test application
Public Class MainAppClass MainApp
Public Sub Main()Sub Main()
Dim context As New Context
'Usually a tree
Dim list As New List(Of AbstractExpression)
'Populate 'abstract syntax tree'
list.Add(New TerminalExpression())
list.Add(New NonterminalExpression())
list.Add(New TerminalExpression())
list.Add(New TerminalExpression())
'Interpret
For Each exp As AbstractExpression In list
exp.Interpret(context)
Next
'Wait for user
Console.ReadLine()
End Sub
End Class
'"Context"
Public Class ContextClass Context
End Class
'"AbstractExpression"
Public MustInherit Class AbstractExpressionClass AbstractExpression
Public MustOverride Sub Interpret()Sub Interpret(ByVal context As Context)
End Class
'"TerminalExpression"
Public Class TerminalExpressionClass TerminalExpression
Inherits AbstractExpression
Public Overrides Sub Interpret()Sub Interpret(ByVal context As Context)
Console.WriteLine("Called TerminalExpression.Interpret")
End Sub
End Class
'"NonterminalExpression"
Public Class NonterminalExpressionClass NonterminalExpression
Inherits AbstractExpression
Public Overrides Sub Interpret()Sub Interpret(ByVal context As Context)
Console.WriteLine("Called NonterminalExpression.Interpret")
End Sub
End Class
一个实例
下面的代码演示利用解释器将罗马数字转化为阿拉伯数字。
实例代码
Imports System
Imports System.Collections
' MainApp test application
Public Class MainAppClass MainApp
Private Shared Sub Main()Sub Main()
Dim roman As String = "MCMXXVIII"
Dim context As New Context(roman)
'Build the 'parse tree'
Dim tree As New ArrayList()
tree.Add(New ThousandExpression())
tree.Add(New HundredExpression())
tree.Add(New TenExpression())
tree.Add(New OneExpression())
' Interpret
For Each exp As Expression In tree
exp.Interpret(context)
Next
Console.WriteLine("{0} = {1}", roman, context.Output)
' Wait for user
Console.Read()
End Sub
End Class
' "Context"
Public Class ContextClass Context
Private m_input As String
Private m_output As Integer
' Constructor
Public Sub New()Sub New(ByVal input As String)
Me.m_input = input
End Sub
' Properties
Public Property Input()Property Input() As String
Get
Return m_input
End Get
Set(ByVal value As String)
m_input = value
End Set
End Property
Public Property Output()Property Output() As Integer
Get
Return m_output
End Get
Set(ByVal value As Integer)
m_output = value
End Set
End Property
End Class
' "AbstractExpression"
Public MustInherit Class ExpressionClass Expression
Public Sub Interpret()Sub Interpret(ByVal context As Context)
If context.Input.Length = 0 Then
Return
End If
If context.Input.StartsWith(Nine()) Then
context.Output += (9 * Multiplier())
context.Input = context.Input.Substring(2)
ElseIf context.Input.StartsWith(Four()) Then
context.Output += (4 * Multiplier())
context.Input = context.Input.Substring(2)
ElseIf context.Input.StartsWith(Five()) Then
context.Output += (5 * Multiplier())
context.Input = context.Input.Substring(1)
End If
While context.Input.StartsWith(One())
context.Output += (1 * Multiplier())
context.Input = context.Input.Substring(1)
End While
End Sub
Public MustOverride Function One()Function One() As String
Public MustOverride Function Four()Function Four() As String
Public MustOverride Function Five()Function Five() As String
Public MustOverride Function Nine()Function Nine() As String
Public MustOverride Function Multiplier()Function Multiplier() As Integer
End Class
' Thousand checks for the Roman Numeral M
' "TerminalExpression"
Public Class ThousandExpressionClass ThousandExpression
Inherits Expression
Public Overloads Overrides Function One()Function One() As String
Return "M"
End Function
Public Overloads Overrides Function Four()Function Four() As String
Return " "
End Function
Public Overloads Overrides Function Five()Function Five() As String
Return " "
End Function
Public Overloads Overrides Function Nine()Function Nine() As String
Return " "
End Function
Public Overloads Overrides Function Multiplier()Function Multiplier() As Integer
Return 1000
End Function
End Class
' Hundred checks C, CD, D or CM
' "TerminalExpression"
Public Class HundredExpressionClass HundredExpression
Inherits Expression
Public Overloads Overrides Function One()Function One() As String
Return "C"
End Function
Public Overloads Overrides Function Four()Function Four() As String
Return "CD"
End Function
Public Overloads Overrides Function Five()Function Five() As String
Return "D"
End Function
Public Overloads Overrides Function Nine()Function Nine() As String
Return "CM"
End Function
Public Overloads Overrides Function Multiplier()Function Multiplier() As Integer
Return 100
End Function
End Class
' Ten checks for X, XL, L and XC
' "TerminalExpression"
Public Class TenExpressionClass TenExpression
Inherits Expression
Public Overloads Overrides Function One()Function One() As String
Return "X"
End Function
Public Overloads Overrides Function Four()Function Four() As String
Return "XL"
End Function
Public Overloads Overrides Function Five()Function Five() As String
Return "L"
End Function
Public Overloads Overrides Function Nine()Function Nine() As String
Return "XC"
End Function
Public Overloads Overrides Function Multiplier()Function Multiplier() As Integer
Return 10
End Function
End Class
' One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX
' "TerminalExpression"
Public Class OneExpressionClass OneExpression
Inherits Expression
Public Overloads Overrides Function One()Function One() As String
Return "I"
End Function
Public Overloads Overrides Function Four()Function Four() As String
Return "IV"
End Function
Public Overloads Overrides Function Five()Function Five() As String
Return "V"
End Function
Public Overloads Overrides Function Nine()Function Nine() As String
Return "IX"
End Function
Public Overloads Overrides Function Multiplier()Function Multiplier() As Integer
Return 1
End Function
End Class
Imports System
Imports System.Collections
' MainApp test application
Public Class MainAppClass MainApp
Private Shared Sub Main()Sub Main()
Dim roman As String = "MCMXXVIII"
Dim context As New Context(roman)
'Build the 'parse tree'
Dim tree As New ArrayList()
tree.Add(New ThousandExpression())
tree.Add(New HundredExpression())
tree.Add(New TenExpression())
tree.Add(New OneExpression())
' Interpret
For Each exp As Expression In tree
exp.Interpret(context)
Next
Console.WriteLine("{0} = {1}", roman, context.Output)
' Wait for user
Console.Read()
End Sub
End Class
' "Context"
Public Class ContextClass Context
Private m_input As String
Private m_output As Integer
' Constructor
Public Sub New()Sub New(ByVal input As String)
Me.m_input = input
End Sub
' Properties
Public Property Input()Property Input() As String
Get
Return m_input
End Get
Set(ByVal value As String)
m_input = value
End Set
End Property
Public Property Output()Property Output() As Integer
Get
Return m_output
End Get
Set(ByVal value As Integer)
m_output = value
End Set
End Property
End Class
' "AbstractExpression"
Public MustInherit Class ExpressionClass Expression
Public Sub Interpret()Sub Interpret(ByVal context As Context)
If context.Input.Length = 0 Then
Return
End If
If context.Input.StartsWith(Nine()) Then
context.Output += (9 * Multiplier())
context.Input = context.Input.Substring(2)
ElseIf context.Input.StartsWith(Four()) Then
context.Output += (4 * Multiplier())
context.Input = context.Input.Substring(2)
ElseIf context.Input.StartsWith(Five()) Then
context.Output += (5 * Multiplier())
context.Input = context.Input.Substring(1)
End If
While context.Input.StartsWith(One())
context.Output += (1 * Multiplier())
context.Input = context.Input.Substring(1)
End While
End Sub
Public MustOverride Function One()Function One() As String
Public MustOverride Function Four()Function Four() As String
Public MustOverride Function Five()Function Five() As String
Public MustOverride Function Nine()Function Nine() As String
Public MustOverride Function Multiplier()Function Multiplier() As Integer
End Class
' Thousand checks for the Roman Numeral M
' "TerminalExpression"
Public Class ThousandExpressionClass ThousandExpression
Inherits Expression
Public Overloads Overrides Function One()Function One() As String
Return "M"
End Function
Public Overloads Overrides Function Four()Function Four() As String
Return " "
End Function
Public Overloads Overrides Function Five()Function Five() As String
Return " "
End Function
Public Overloads Overrides Function Nine()Function Nine() As String
Return " "
End Function
Public Overloads Overrides Function Multiplier()Function Multiplier() As Integer
Return 1000
End Function
End Class
' Hundred checks C, CD, D or CM
' "TerminalExpression"
Public Class HundredExpressionClass HundredExpression
Inherits Expression
Public Overloads Overrides Function One()Function One() As String
Return "C"
End Function
Public Overloads Overrides Function Four()Function Four() As String
Return "CD"
End Function
Public Overloads Overrides Function Five()Function Five() As String
Return "D"
End Function
Public Overloads Overrides Function Nine()Function Nine() As String
Return "CM"
End Function
Public Overloads Overrides Function Multiplier()Function Multiplier() As Integer
Return 100
End Function
End Class
' Ten checks for X, XL, L and XC
' "TerminalExpression"
Public Class TenExpressionClass TenExpression
Inherits Expression
Public Overloads Overrides Function One()Function One() As String
Return "X"
End Function
Public Overloads Overrides Function Four()Function Four() As String
Return "XL"
End Function
Public Overloads Overrides Function Five()Function Five() As String
Return "L"
End Function
Public Overloads Overrides Function Nine()Function Nine() As String
Return "XC"
End Function
Public Overloads Overrides Function Multiplier()Function Multiplier() As Integer
Return 10
End Function
End Class
' One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX
' "TerminalExpression"
Public Class OneExpressionClass OneExpression
Inherits Expression
Public Overloads Overrides Function One()Function One() As String
Return "I"
End Function
Public Overloads Overrides Function Four()Function Four() As String
Return "IV"
End Function
Public Overloads Overrides Function Five()Function Five() As String
Return "V"
End Function
Public Overloads Overrides Function Nine()Function Nine() As String
Return "IX"
End Function
Public Overloads Overrides Function Multiplier()Function Multiplier() As Integer
Return 1
End Function
End Class
Chain of Responsibility模式的几个要点:
1、Interpreter模式的应用场合是Interpreter模式应用中的难点,只有满足“业务规则频繁变化,且类似的模式不断重复出现,并且容易抽象为语法规则的问题”才适合使用Interpreter模式。
2、使用Interpreter模式来表示文法规则,从而可以使用面向对象技巧来方便地“扩展”文法。
3、Interpreter模式比较适合简单的文法表示,对于复杂的文法表示,Interpreter模式会产生比较大的类层次结构,需要求助于语法分析生成器这样的标准工具。
我的理解
封装特定领域变化,支持领域问题的频繁变化。
参考资料
《C#面向对象设计模式纵横谈系列课程(16)》 李建中老师