一文搞懂解释器模式

原理

为新的"语言"定义语法规则,定义一个解释器用来解释语法

实现核心

将不同操作符的操作拆分到单独的操作符表达式类里面,避免大而全的解析类

最佳实践1

需求背景

假设我们定义了一个新的加减乘除计算“语言”,语法规则如下:
运算符只包含加、减、乘、除,并且没有优先级的概念;
表达式(也就是前面提到的“句子”)中,先书写数字,后书写运算符,空格隔开;
按照先后顺序,取出两个数字和一个运算符计算结果,结果重新放入数字的最头部位置,循环上述过程,直到只剩下一个数字,这个数字就是表达式最终的计算结果。

比如“ 8 3 2 4 - + * ”这样一个表达式,我们按照上面的语法规则来处理,取出数字“8 3”和“-”运算符,计算得到 5,于是表达式就变成了“ 5 2 4 + * ”。然后,我们再取出“ 5 2 ”和“ + ”运算符,计算得到 7,表达式就变成了“ 7 4 * ”。最后,我们取出“ 7 4”和“ * ”运算符,最终得到的结果就是 28。

实现版本1

type ExpressionInterpreter struct{}

func (i *ExpressionInterpreter) Interpreter(s string) int64 {
	strList := strings.Split(s, " ")
	numberQueue := queue.New()
	for i := 0; i < (len(strList)+1)/2; i++ {
		num, _ := strconv.ParseInt(strList[i], 10, 64)
		numberQueue.PushBack(num)
	}
	for i := (len(strList) + 1) / 2; i < len(strList); i++ {
		var result int64
		num1 := numberQueue.PopFront().(int64)
		num2 := numberQueue.PopFront().(int64)
		sign := strList[i]
		if sign == "+" {
			result = num1 + num2
		} else if sign == "-" {
			result = num1 - num2
		} else if sign == "*" {
			result = num1 * num2
		} else if sign == "/" {
			result = num1 / num2
		} else {
			panic("illegal sign")
		}
		numberQueue.PushFront(result)
	}
	if numberQueue.Len() != 1 {
		panic("expression illegal")
	}
	return numberQueue.PopFront().(int64)
}

这里每个运算符的逻辑比较简单,所以放在一个类中没有问题,但是如果每个运算符的逻辑都很复杂,就会导致这个类很大,可读性下降,所以我们可以将每个运算符的逻辑拆成单独的类

实现版本2

type Expression interface {
	Interpreter() int64
}

type NumExpression struct {
	num int64
}

func NewNumExpression(num int64) *NumExpression {
	return &NumExpression{
		num: num,
	}
}

func (e *NumExpression) Interpreter() int64 {
	return e.num
}

type AddExpression struct {
	leftExp  Expression
	rightExp Expression
}

func NewAddExpression(leftExp Expression, rightExp Expression) *AddExpression {
	return &AddExpression{
		leftExp:  leftExp,
		rightExp: rightExp,
	}
}

func (e *AddExpression) Interpreter() int64 {
	return e.leftExp.Interpreter() + e.rightExp.Interpreter()
}

type SubtractExpression struct {
	leftExp  Expression
	rightExp Expression
}

func NewSubtractExpression(leftExp Expression, rightExp Expression) *SubtractExpression {
	return &SubtractExpression{
		leftExp:  leftExp,
		rightExp: rightExp,
	}
}

func (e *SubtractExpression) Interpreter() int64 {
	return e.leftExp.Interpreter() - e.rightExp.Interpreter()
}

type MulExpression struct {
	leftExp  Expression
	rightExp Expression
}

func NewMulExpression(leftExp Expression, rightExp Expression) *MulExpression {
	return &MulExpression{
		leftExp:  leftExp,
		rightExp: rightExp,
	}
}

func (e *MulExpression) Interpreter() int64 {
	return e.leftExp.Interpreter() * e.rightExp.Interpreter()
}

type DivisionExpression struct {
	leftExp  Expression
	rightExp Expression
}

func NewDivisionExpression(leftExp Expression, rightExp Expression) *DivisionExpression {
	return &DivisionExpression{
		leftExp:  leftExp,
		rightExp: rightExp,
	}
}

func (e *DivisionExpression) Interpreter() int64 {
	return e.leftExp.Interpreter() / e.rightExp.Interpreter()
}

func (i *ExpressionInterpreter) InterpreterV2(s string) int64 {
	strList := strings.Split(s, " ")
	numberQueue := queue.New()
	for i := 0; i < (len(strList)+1)/2; i++ {
		num, _ := strconv.ParseInt(strList[i], 10, 64)
		numberQueue.PushBack(num)
	}
	for i := (len(strList) + 1) / 2; i < len(strList); i++ {
		var result int64
		num1 := NewNumExpression(numberQueue.PopFront().(int64))
		num2 := NewNumExpression(numberQueue.PopFront().(int64))
		sign := strList[i]
		var expression Expression
		if sign == "+" {
			expression = NewAddExpression(num1, num2)
		} else if sign == "-" {
			expression = NewSubtractExpression(num1, num2)
		} else if sign == "*" {
			expression = NewMulExpression(num1, num2)
		} else if sign == "/" {
			expression = NewDivisionExpression(num1, num2)
		} else {
			panic("illegal sign")
		}
		result = expression.Interpreter()
		numberQueue.PushFront(result)
	}
	if numberQueue.Len() != 1 {
		panic("expression illegal")
	}
	return numberQueue.PopFront().(int64)
}

最佳实践2

需求背景

在我们平时的项目开发中,监控系统非常重要,它可以时刻监控业务系统的运行情况,及时将异常报告给开发者。比如,如果每分钟接口出错数超过 100,监控系统就通过短信、微信、邮件等方式发送告警给开发者。
一般来讲,监控系统支持开发者自定义告警规则,比如我们可以用下面这样一个表达式,来表示一个告警规则,它表达的意思是:
每分钟 API 总出错数超过 100 或者每分钟 API 总调用数超过 10000 就触发告警。
api_error_per_minute > 100 || api_count_per_minute > 10000

我们假设自定义的告警规则只包含“||、&&、>、<、”这五个运算符,其中,“>、<、”运算符的优先级高于“||、&&”运算符,“&&”运算符优先级高于“||”。在表达式中,任意元素之间需要通过空格来分隔。除此之外,用户可以自定义要监控的 key,比如前面的 api_error_per_minute、api_count_per_minute。

代码实现

type AlterExpression interface {
	Interpreter(stats map[string]int) bool
}

type GreaterExpression struct {
	key   string
	value int
}

func NewGreaterExpression(key string, value int) *GreaterExpression {
	return &GreaterExpression{
		key:   key,
		value: value,
	}
}

func (e *GreaterExpression) Interpreter(stats map[string]int) bool {
	v, ok := stats[e.key]
	if ok == false {
		return false
	}
	return v > e.value
}

type LessExpression struct {
	key   string
	value int
}

func NewLessExpression(key string, value int) *LessExpression {
	return &LessExpression{
		key:   key,
		value: value,
	}
}

func (e *LessExpression) Interpreter(stats map[string]int) bool {
	v, ok := stats[e.key]
	if ok == false {
		return false
	}
	return v < e.value
}

type EqualExpression struct {
	key   string
	value int
}

func NewEqualExpression(key string, value int) *EqualExpression {
	return &EqualExpression{
		key:   key,
		value: value,
	}
}

func (e *EqualExpression) Interpreter(stats map[string]int) bool {
	v, ok := stats[e.key]
	if ok == false {
		return false
	}
	return e.value == v
}

type AndExpression struct {
	expressionList []AlterExpression
}

func NewAndExpression(rule string) *AndExpression {
	strList := strings.Split(rule, `&&`)
	expList := make([]AlterExpression, 0, len(strList))
	for i := range strList {
		str := strings.Trim(strList[i], " ")
		opStrList := strings.Split(str, " ")
		sign := opStrList[1]
		key := opStrList[0]
		valueStr := opStrList[2]
		value, _ := strconv.ParseInt(valueStr, 10, 64)
		if sign == ">" {
			expList = append(expList, NewGreaterExpression(key, int(value)))
		} else if sign == "<" {
			expList = append(expList, NewLessExpression(key, int(value)))
		} else if sign == "" {
			expList = append(expList, NewEqualExpression(key, int(value)))
		} else {
			panic("illegal op")
		}
	}
	return &AndExpression{
		expressionList: expList,
	}
}

func (e *AndExpression) Interpreter(stats map[string]int) bool {
	for i := range e.expressionList {
		expression := e.expressionList[i]
		if expression.Interpreter(stats) == false {
			return false
		}
	}
	return true
}

type OrExpression struct {
	expressionList []AlterExpression
}

func NewOrExpression(rule string) *OrExpression {
	strList := strings.Split(rule, `||`)
	expList := make([]AlterExpression, 0, len(strList))
	for i := range strList {
		str := strings.Trim(strList[i], " ")
		expList = append(expList, NewAndExpression(str))
	}
	return &OrExpression{
		expressionList: expList,
	}
}

func (e *OrExpression) Interpreter(stats map[string]int) bool {
	for i := range e.expressionList {
		expression := e.expressionList[i]
		if expression.Interpreter(stats) {
			return true
		}
	}
	return false
}

type AlterRuleInterpreter struct {
	expression AlterExpression
}

func NewAlterRuleInterpreter(ruleExpression string) *AlterRuleInterpreter {
	return &AlterRuleInterpreter{
		expression: NewOrExpression(ruleExpression),
	}
}

func (i *AlterRuleInterpreter) Interpreter(stats map[string]int) bool {
	return i.expression.Interpreter(stats)
}

func ApplicationTest() {
	rule := "key1 > 100 && key2 < 30 || key3 < 100 || key4 == 88"
	alterRuleInterpreter := NewAlterRuleInterpreter(rule)
	stats := map[string]int{
		"key1": 101,
		"key2": 18,
		"key3": 121,
		"key4": 88,
	}
	alter := alterRuleInterpreter.Interpreter(stats)
	if alter {
		println("报警!!!")
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值