interface - 用接口(interface)来干燥我的 Go 函数

标签 interface struct go

我有以下功能:

func (r *Resource) Create(kind string, data io.ReadCloser) (err error) {
  decoder := json.NewDecoder(data)
  r.Kind = kind

  switch kind {
  case "user":
    var user User
    if err = decoder.Decode(&user); err != nil {
      panic(err)
    }

    if err = user.Save(r.Context); err != nil {
      panic(err)
    }

    r.Data = user
    break

  case "space":
    var space Space
    if err = decoder.Decode(&space); err != nil {
      panic(err)
    }

    if err = space.Save(r.Context); err != nil {
      panic(err)
    }

    r.Data = space
    break

  case "room":
    var room Room
    if err = decoder.Decode(&room); err != nil {
      panic(err)
    }

    if err = room.Save(r.Context); err != nil {
      panic(err)
    }

    r.Data = room
    break

  case "element":
    var element Element
    if err = decoder.Decode(&element); err != nil {
      panic(err)
    }

    if err = element.Save(r.Context); err != nil {
      panic(err)
    }

    r.Data = element
    break

  default:
    break
  }
  return
}

如您所见,除了接收 JSON 数据的结构类型之外,开关中的每个 case 都是相同的。

我怀疑接口(interface)和类型断言中有答案。

编辑:

我能够将保存部分分解为一个单独的方法,但我仍然无法找到一种无需 switch 语句即可将 JSON 对象解码为适当结构的好方法。

func (r *Resource) Create(kind string, data io.ReadCloser) (err error) {
  decoder := json.NewDecoder(data)
  r.Kind = kind

  switch kind {
  case "user":
    var user User
    if err = decoder.Decode(&user); err != nil {
      panic(err)
    }
    r.saveEntity(&user)
    break

  case "space":
    var space Space
    if err = decoder.Decode(&space); err != nil {
      panic(err)
    }
    r.saveEntity(&space)
    break

  case "room":
    var room Room
    if err = decoder.Decode(&room); err != nil {
      panic(err)
    }
    r.saveEntity(&room)
    break

  case "element":
    var element Element
    if err = decoder.Decode(&element); err != nil {
      panic(err)
    }
    r.saveEntity(&element)
    break

  default:
    break
  }
  return
}

func (r *Resource) saveEntity(e Entity) {
  if err := e.Save(r.Context); err != nil {
    panic(err)
  }

  r.Data = e
}

最佳答案

您可以将实例化移动到单行函数并创建一个映射来映射 适合各自的实例化函数。其余代码应该可以重用。

示例:

kinds := map[string]func() Entity {
    "user": func() Entity { return &User{} },
    "space": func() Entity { return &Space{} },
    "room": func() Entity { return &Room{} },
}

func Create(kind string) {
    instance := kinds[kind]()

    decoder.Decode(instance)

    saveEntity(instance)
}

关于interface - 用接口(interface)来干燥我的 Go 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17507697/

相关文章:

c# - 具体类实现中的 IEnumerable 与 List

c++ - 包含两个整数(并且只有两个整数)的结构是否保证是 sizeof(int) 的两倍大?

c - 返回指向 C 中结构的指针

go - golang 中的嵌套 map 创建

戈朗。重构||图案||任何解决方案

mongodb - mongo-go-driver聚合查询总是返回 "Current": null

interface - 实现一个没有错误的接口(interface)

go - 接口(interface)与实现

C# 接口(interface)。不指定派生类名

c - "Error: unknown type name"- 在函数声明中使用结构别名