Go 設計模式 -- 解釋器模式

大家好,這裏是每週都在陪你一起進步的網管~!今天繼續學習設計模式—解釋器模式

解釋器模式是一種行爲設計模式,可以用來在程序裏創建針對一個特點領域語言的解釋器,用於處理解釋領域語言中的語句。換句話說,該模式定義了領域語言的抽象語法樹以及用示來解釋語法樹的解釋器。

模式使用場景

解釋器模式,用於解決需要解釋語言中的句子或表達式的問題。以下是一些可以在 程序中使用解釋器模式的真實場景:

雖然解釋器模式可以用來解決這些問題,但它並不總是最好的解決方案。對於複雜的語言,使用特定的解析庫或工具或其他設計模式可能更有效。

下面我們先來學習一下解釋器模式的結構組成,然後再嘗試用代碼自己實現一個解釋器。

模式構成

解釋器模式中的關鍵組件有:

下面是解釋器模式構成的 UML 類圖:

看完解釋器模式的結構組成後,我們接下來嘗試應用解釋器模式,用代碼實現一個加法運算的解釋器。

實現解釋器模式

看了上面解釋器的結構組成後我們結下來通過代碼一步步實現其核心組件來演示怎麼用代碼實現解釋器模式。

以下是如何在 Go 中實現解釋器模式的步驟。

  1. 定義表示抽象語法樹中元素的表達式接口。

  2. 創建實現 Expression 接口的具體表達式結構,例如 TerminalExpression 和 NonTerminalExpression。

  3. 定義一個上下文結構來保存解釋過程中可能需要的任何必要數據或狀態(這一步可選)。

  4. 創建解析器或構建器以根據輸入表達式構造抽象語法樹。 使用創建的抽象語法樹和上下文解釋表達式。

這裏簡單實現一個加減的運算器,我們對每種運算定義對應的 Expression 對象,在方法裏實現具體的運算規則,避免所有的運算操作放到一個函數中,這體現瞭解釋器模式的核心思想,將語法解析的工作拆分到各個小類中,以此來避免大而全的解析類。

我們先按照上面的步驟一,定義數學運算這一領域語言裏表示抽象語法樹中元素的表達式接口:

type Expression interface {
 Interpret() int
}

接下來創建 Expression 接口的具體實現類,在我們的加減法運算中需要實現操作數、加法、減法對應的實現類。

"本文使用的完整可運行源碼
去公衆號「網管叨bi叨」發送【設計模式】即可領取"
type NumberExpression struct {
 val int
}
// 解釋--返回其整數值
func (n *NumberExpression) Interpret() int {
 return n.val
}

// 加法運算
type AdditionExpression struct {
 left, right Expression
}
// 解釋--進行加法操作
func (n *AdditionExpression) Interpret() int {
 return n.left.Interpret() + n.right.Interpret()
}
// 減法運算
type SubtractionExpression struct {
 left, right Expression
}
// 解釋--進行減法運算
func (n *SubtractionExpression) Interpret() int {
 return n.left.Interpret() - n.right.Interpret()
}

最後我們創建一個表達式解析器,它會根據輸入表達式構造抽象語法樹,使用創建的抽象語法樹和上下文解釋表達式。

"本文使用的完整可運行源碼
去公衆號「網管叨bi叨」發送【設計模式】即可領取"
type Parser struct {
 exp   []string
 index int
 prev  Expression
}

func (p *Parser) Parse(exp string) {
 p.exp = strings.Split(exp, " ")

 for {
  if p.index >= len(p.exp) {
   return
  }
  switch p.exp[p.index] {
  case "+":
   p.prev = p.newAdditionExpression()
  case "-":
   p.prev = p.newSubtractionExpression()
  default:
   p.prev = p.newNumberExpression()
  }
 }
}

func (p *Parser) newAdditionExpression() Expression {
 p.index++
 return &AdditionExpression{
  left:  p.prev,
  right: p.newNumberExpression(),
 }
}

func (p *Parser) newSubtractionExpression() Expression {
 p.index++
 return &SubtractionExpression{
  left:  p.prev,
  right: p.newNumberExpression(),
 }
}

func (p *Parser) newNumberExpression() Expression {
 v, _ := strconv.Atoi(p.exp[p.index])
 p.index++
 return &NumberExpression{
  val: v,
 }
}
// 返回Expression實例
// 調用Interpret方法會從右向左遞歸計算出公式結果
func (p *Parser) Result() Expression {
 return p.prev
}

最後,我們用使用 Parse 把客戶端傳遞過來的加減法表達式解析成抽象語法樹,然後運行解釋器計算加減法表達式的結果。

"本文使用的完整可運行源碼
去公衆號「網管叨bi叨」發送【設計模式】即可領取"
func main() {
 p := &Parser{}
 p.Parse("1 + 3 + 3 + 3 - 3")
 res := p.Result().Interpret()
 expect := 7
 if res != expect {
  log.Fatalf("error: expect %d got %d", expect, res)
 }

 fmt.Printf("expect: %d, got: %d", expect, res)
}

本文的完整源碼,已經同步收錄到我整理的電子教程裏啦,可向我的公衆號「網管叨 bi 叨」發送關鍵字【設計模式】領取。

總結

在程序中使用解釋器模式的目標是: 定義特定於領域的語言及其語法,使用 AST(抽象語法樹)表示語言中的表達式或句子,好讓程序能夠根據一組規則或操作解釋或評估表達式

最後我們再來列舉一下解釋器模式的優缺點。 使用解釋器模式的優點是:

使用解釋器模式的缺點是:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/8v0UZWygCvkbye4Y0P-3sQ