在Go

时间:2017-04-24 04:26:14

标签: go

我想设置一个强制执行以下行为的界面。实现Rules接口的结构实现prepareData()函数,它们包含Evaluate()准备好的数据的条件,并返回结果。如果数据通过所有条件,则可以触发操作。

可能有不同的结构实现此规则界面,例如JSONRules对象,如下例所示,其中准备好的数据采用JSON格式,JSON条件只检查JSON对象中字段的值。或者它可能是完全不同的东西,例如获取URL并检查HTTP状态是否可达200​​.

设计中有3个目标:

  1. 主程序应该与实现无关,例如无论是JSONRules还是正在执行的URLRules。它应该只能说Do(规则),例如做你必须做的事情并让我知道结果。

  2. 执行顺序,例如prepareData(),evaluateConditions()应该被抽象,因为它对所有规则都是相同的,我们不应该再重写它。

  3. 作为执行顺序的一部分,动作将通过一个独立的专用组件触发,该组件可能是一个外部API,这是该部分应该被抽象而不是由每个人重新实现的另一个原因。规则。

  4. 下面是我如何实现这一点的示例。我面临的问题是数据和每个条件评估数据的方式对于每个实现都是不同的,这意味着Condition接口不能知道某些字段或函数,但是,实现需要遵循接口。因此,我在以下示例中得到“data.actualValue undefined(类型Data is interface with without methods)”错误。

    如果我不解释这个问题,代码应该说明一切。 Go中是否有任何设计模式可以帮助克服Go中接口的限制?

    以下是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 个答案:

没有答案