Go:我如何检查具体类型由哪种嵌入类型组成?

时间:2017-05-11 09:56:14

标签: go composition embedding

我怀疑我正在试图以一种OOP方式行事,但我不知道去做我想做的事情。

我有一个Message结构,用于在客户端 - 服务器应用程序中传递数据:

type Message struct {
    ID   string      `json:"id,omitempty"`
    Type string      `json:"type"`
    Data interface{} `json:"data"`
}

这里的数据可以是不同的东西,例如许多命令:

type Command struct {
    User *types.UserInfo `json:"user"`
}

type CommandA struct {
    Command
    A *AData `json:"a_data"`
}

type CommandB struct {
    CommandB
    B *BData `json:"b_data"`

}

我想要做的是检查消息数据类型是否为命令并执行所有命令共有的操作,例如授权,所有操作都在一个地方,而不必键入断言什么类型的命令,调用适当的处理函数然后执行auth,因为这会导致大量的代码重复。

下面的代码反映了我想要发生的事情。

for {
    select {
    case m := <-in:
      // what I would like to do, obviously not working as
      // m.Data is not of type Command but the actual command type
      if c, ok := m.Data.(msg.Command); ok {
        // do auth and other common stuff
      }
      switch t := m.Data.(type) {
      case *msg.CommandA:
        go srv.handleCommandA(m.ID, t)
      case *msg.CommandB:
        go srv.handleCommandB(m.ID, t)
      // etc etc
      default:
        // do something
      }
   }
}

如何解决这个问题呢?

2 个答案:

答案 0 :(得分:2)

您可以在界面

中定义常用命令
type Commander interface{
    DoCommonStuff()
}

为Command struct

实现它
func (c Command) DoCommonStuff(){
//do stuff
}

然后断言

if c, ok := m.Data.(Commander); ok {
    c.DoCommonStuff()
}

您的其他代码应该保持不变

答案 1 :(得分:0)

一种方法是使用反射从Data中提取公共字段值。在您的示例中,由于所有Command都有User字段,因此我们可以使用它来确定Message.Data是否为命令。如果数据未嵌入Command,只需返回nil即可。示例代码:

func GetUserInfo(v interface{}) *types.UserInfo {
    vt := reflect.ValueOf(v)
    if vt.Kind() == reflect.Ptr {
        vt = vt.Elem()
    }
    if vt.Kind() != reflect.Struct {
        return nil
    }

    u := vt.FieldByName("User")
    if !u.IsValid() {
        return nil
    }

    user, ok := u.Interface().(*types.UserInfo)
    if !ok {
        return nil
    }

    return user
}

//Call GetUserInfo then perform common operation
user := GetUserInfo(m.Data)
if user != nil {
    //Do auth and other common stuff
}