英文:
DRY out my Go function with interfaces
问题
我有以下的函数:
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
}
如你所见,switch语句中的每个case除了接收JSON数据的结构体类型不同外,其他部分都是相同的。
我怀疑接口和类型断言中有一个答案。
编辑:
我已经将保存部分拆分为一个单独的方法,但我仍然无法找到一种好的方法来将JSON对象解码为适当的结构体,而不使用switch语句。
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
}
英文:
I have the following function:
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
}
As you can see, each case in the switch is identical except for the type of the struct that receives the JSON data.
I suspect that there's an answer in interfaces and type assertion.
EDIT:
I was able to break out the saving part into a separate method, but I still can't figure out a good way to decode the JSON object into the appropriate struct without the switch statement.
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
}
答案1
得分: 2
你可以将实例化移动到一行函数中,并创建一个映射,将种类映射到相应的实例化函数。代码的其余部分应该是可重用的。
示例:
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)
}
英文:
You could move the instantiation to one-line functions and create a mapping which maps the
kind to the respective instantiation function. The rest of the code should be re-usable.
Example:
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论