Design Pattern: Interpreter Pattern in Go

Interpreter pattern is used to represent common operations. If we want to implement any custom rule/calculation/operations/language then we can use the interpreter pattern.

This article demonstrates Interpreter pattern implementations in Golang. Check the following examples.

Implementation

Here are the steps for Interpreter pattern implementation in Golang-

  • Create an interface for the operations.
  • Create a struct for the terminal operation. This is the main operation struct. Define the main operation/calculation in the method, which is defined for execution. This struct should implement the interface.
  • Define struct for each operation. Declare fields in the struct to store the operands, of type of the operation interface. In the execution method perform the operation.

Examples

Here are a few examples of Interpreter pattern implementation in Go-

Example #1: Logical Operation

Let’s take the example of operations like AND, OR, XOR, etc. We are checking if a string contains any specific string(sub-string), and we will evaluate the operations AND, OR, XOR etc. based on that.

Operation Interface

  • Create file “operation.go”.
  • Define interface “Operation”.
  • Declare method “Execute”.
// operation.go

package main

type Operation interface {
	Execute(opContext string) bool
}

Terminal Operation Struct

  • Create file “terminal_operation.go”.
  • Define struct “TerminalOpertion”.
  • Declare field “data” of type of string.
  • Create method “NewTerminalOperation”, which will generate a new struct and set the data value.
  • Implement interface “Operation” for the struct. Define method “Execute” as part of the interface implementation.
  • In the “Execute” method check if the passed string contains the “data” filled value.
// terminal_operation.go

package main

import "strings"

type TerminalOperation struct {
	data string
}

func NewTerminalOperation(data string) (terminalOperation *TerminalOperation) {
	terminalOperation = &TerminalOperation{}
	terminalOperation.data = data
	return
}

func (terminalOperation *TerminalOperation) Execute(opContext string) bool {
	return strings.Contains(opContext, terminalOperation.data)
}

AND Operation Struct

  • Create file “and_operation.go”.
  • Define struct “AndOperation”.
  • Declare fields “op1” and “op2” of the type of “Opertion”.
  • Create method “NewAndOperation”, which will generate a new struct and set the field values.
  • Implement interface “Operation” for the struct.
  • In the “Execute” method call the “Execute” methods from the “op1” and “op2” and the perform “AND” (&&) operation on those two operands.
// and_operation.go

package main

type AndOperation struct {
	op1 Operation
	op2 Operation
}

func NewAndOperation(op1 Operation, op2 Operation) (andOperation *AndOperation) {
	andOperation = &AndOperation{}
	andOperation.op1 = op1
	andOperation.op2 = op2
	return
}

func (andOperation *AndOperation) Execute(opContext string) bool {
	return andOperation.op1.Execute(opContext) && andOperation.op2.Execute(opContext)
}

OR Operation Struct

  • Create file “or_operation.go”.
  • Define struct “OrOperation”.
  • Declare fields “op1” and “op2” of the type of “Operation”.
  • Create method “NewOrOperation”, to generate a new struct and set the field values.
  • Implement interface “Operation” for the struct. In the “Execute” method call the “Execute” methods from the “op1” and “op2” and the perform “OR” (||) operation on those two operands.
// or_operation.go

package main

type OrOperation struct {
	op1 Operation
	op2 Operation
}

func NewOrOperation(op1 Operation, op2 Operation) (orOperation *OrOperation) {
	orOperation = &OrOperation{}
	orOperation.op1 = op1
	orOperation.op2 = op2
	return
}

func (orOperation *OrOperation) Execute(opContext string) bool {
	return orOperation.op1.Execute(opContext) || orOperation.op2.Execute(opContext)
}

XOR Operation Struct

  • Create file “xor_operation.go”.
  • Define struct “XorOperation”.
  • Declare fields “op1” and “op2” of the type of “Operation”.
  • Create method “NewXorOperation”.
  • Implement interface “Operation” for the struct. In the “Execute” method call the “Execute” methods from the “op1” and “op2” and the perform “XOR” operation on those two operands.
// xor_operation.go

package main

type XorOperation struct {
	op1 Operation
	op2 Operation
}

func NewXorOperation(op1 Operation, op2 Operation) (xorOperation *XorOperation) {
	xorOperation = &XorOperation{}
	xorOperation.op1 = op1
	xorOperation.op2 = op2
	return
}

func (xorOperation *XorOperation) Execute(opContext string) bool {
	return xorOperation.op1.Execute(opContext) != xorOperation.op2.Execute(opContext)
}

Demo

For using the implementation, we can create 2 “TerminalOperation” and then define AND/OR/XOR operations.

Then we can call the “Execute” method and perform the operations.

// main.go

package main

import "fmt"

func main() {
	op1 := NewTerminalOperation("Big")
	op2 := NewTerminalOperation("Box")

	andChecker := NewAndOperation(op1, op2)
	orChecker := NewOrOperation(op1, op2)
	xorChecker := NewXorOperation(op1, op2)

	checkStr1 := "Big Box Code"
	checkStr2 := "Only Big Code"
	checkStr3 := "Only Box Code"
	checkStr4 := "No Code"

	andResult1 := andChecker.Execute(checkStr1)
	andResult2 := andChecker.Execute(checkStr2)
	andResult3 := andChecker.Execute(checkStr3)
	andResult4 := andChecker.Execute(checkStr4)

	fmt.Printf("Data: %v; AND Result: %v\n", checkStr1, andResult1)
	fmt.Printf("Data: %v; AND Result: %v\n", checkStr2, andResult2)
	fmt.Printf("Data: %v; AND Result: %v\n", checkStr3, andResult3)
	fmt.Printf("Data: %v; AND Result: %v\n", checkStr4, andResult4)

	orResult1 := orChecker.Execute(checkStr1)
	orResult2 := orChecker.Execute(checkStr2)
	orResult3 := orChecker.Execute(checkStr3)
	orResult4 := orChecker.Execute(checkStr4)

	fmt.Printf("Data: %v; OR Result: %v\n", checkStr1, orResult1)
	fmt.Printf("Data: %v; OR Result: %v\n", checkStr2, orResult2)
	fmt.Printf("Data: %v; OR Result: %v\n", checkStr3, orResult3)
	fmt.Printf("Data: %v; OR Result: %v\n", checkStr4, orResult4)

	xorResult1 := xorChecker.Execute(checkStr1)
	xorResult2 := xorChecker.Execute(checkStr2)
	xorResult3 := xorChecker.Execute(checkStr3)
	xorResult4 := xorChecker.Execute(checkStr4)

	fmt.Printf("Data: %v; XOR Result: %v\n", checkStr1, xorResult1)
	fmt.Printf("Data: %v; XOR Result: %v\n", checkStr2, xorResult2)
	fmt.Printf("Data: %v; XOR Result: %v\n", checkStr3, xorResult3)
	fmt.Printf("Data: %v; XOR Result: %v\n", checkStr4, xorResult4)
}

Output

Output will be as below.

Data: Big Box Code; AND Result: true
Data: Only Big Code; AND Result: false
Data: Only Box Code; AND Result: false
Data: No Code; AND Result: false

Data: Big Box Code; OR Result: true
Data: Only Big Code; OR Result: true
Data: Only Box Code; OR Result: true
Data: No Code; OR Result: false

Data: Big Box Code; XOR Result: false
Data: Only Big Code; XOR Result: true
Data: Only Box Code; XOR Result: true
Data: No Code; XOR Result: false

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Interpreter pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.