dongnuo3749 2017-04-24 04:26
浏览 31

克服Go中复杂设计中的界面限制

I want to set an interface that enforces the following behavior. Structs that implement the Rules interface, implement a prepareData() function, they contain Conditions that Evaluate() the prepared data, and return a result. If the data passes all conditions, actions can be triggered.

There may be different structs that implement this Rules interface e.g. a JSONRules object as in the example below, where the prepared data are in JSON format, and a JSON Condition that simply checks for a value of a field in the JSON object. Or it could be something completely different e.g. GET a URL and check if it is reachable with HTTP status is 200.

There's 3 objectives in the design:

  1. The main program should be agnostic to the implementation e.g. whether it's JSONRules or a URLRules that it's executing. It should simply be able to say Do(Rules) e.g. do what you have to do and let me know the result.

  2. The sequence of execution e.g. prepareData(), evaluateConditions() should be abstracted since it is the same for all Rules and we shouldn't have to write it all over again.

  3. As part of the sequence of execution, actions will be triggered via a separate, specialized component which could be an external API, which is one more reason that this part should be abstracted and not re-implemented by each individual rules.

Below is an example of how I went about implementing this. The problem that I face is that the Data and the way the data are evaluated by each Condition are different for every implementation, which means that the Condition interface cannot be aware of certain fields or functions, but yet, the implementations need to follow the interfaces. I therefore get a "data.actualValue undefined (type Data is interface with no methods)" error in the following example.

The code should speak for itself, if I'm not explaining this well. Are there are any design pattern in Go that would help overcoming the limitations in interfaces in Go?

Here is a link to the code at the Go Playground: https://play.golang.org/p/G9XnEZ74bM

package main

import (
  "fmt"
)

func main() {
  condition := JSONCondition{ "Expected Value" }
  rules := JSONRules{
    RulesBase{
      data : nil,
      conditions : []Condition{ condition },
    },
  }                                                                                                                                                                                                                         
  Do(rules)
}

type Rules interface {
  getData() Data
  getConditions() []Condition
  prepareData()
  evaluateConditions() bool
}

type RulesBase struct {
  data         Data
  conditions []Condition
}

func (rules RulesBase) getData() Data {
  return rules.data
}

func (rules RulesBase) getConditions() []Condition {
  return rules.conditions
}

func (rules RulesBase) evaluateConditions() bool {
  allOk := true
  for _, condition := range rules.getConditions() {
    ok := condition.Evaluate(rules.getData())
    if !ok {
      allOk = false
      break
    }
  }  

  return allOk
}

func Do(rules Rules) {
  rules.prepareData()
  ok := rules.evaluateConditions()

  if ok {
    // Take some actions if the conditions evaluated successfully.                                                                                                                                                                           
    fmt.Println("Conditions passed.")
  }
}

type Data interface {}

type Condition interface {
  Evaluate(Data) bool
}

type JSONRules struct {
  RulesBase
  // Could have additional fields that would be used to prepare the data such as                                                                                                                                                             
  // a URL to fetch data from in the prepareData() function.                                                                                                                                                                                 
}

func (rules JSONRules) prepareData() {
  rules.data = JSONData {
    actualValue : "Expected Value",
  }
}

type JSONData struct {
  actualValue string
}

type JSONCondition struct {
  expectedValue string
}

func (condition JSONCondition) Evaluate(data Data) bool {
  if data.actualValue == condition.expectedValue {
    return true
  }

  return false
}
  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 对于相关问题的求解与代码
    • ¥15 ubuntu子系统密码忘记
    • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
    • ¥15 保护模式-系统加载-段寄存器
    • ¥15 电脑桌面设定一个区域禁止鼠标操作
    • ¥15 求NPF226060磁芯的详细资料
    • ¥15 使用R语言marginaleffects包进行边际效应图绘制
    • ¥20 usb设备兼容性问题
    • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊
    • ¥15 安装svn网络有问题怎么办