通过其父结构的方法更改嵌入结构的属性

huangapple go评论88阅读模式
英文:

Changing a property of a embedded struct using a method from it's parent

问题

我必须定期调用父结构的一个方法,但在调用时,它必须更新嵌入结构的特定属性(在我的情况下,这些结构具有不同的id数据类型)。

我能想到的唯一解决方案是重写父结构的一个方法,这样,当再次调用周期性方法时,它将使用嵌入结构的方法而不是父结构的原始方法。

代码如下所示:

package main

import (
	"fmt"
)

type Fruit struct {
	image *Image
	tree  *Tree

	SetImage func(*Image)
	SetTree  func(*Tree) // #2 (always nil for Strawberry)
}

func NewFruit() *Fruit {
	f := &Fruit{}
	f.SetImage = f.setImage
	f.SetTree = f.setTree
	return f
}

func (f *Fruit) Image() *Image {
	return f.image
}
func (f *Fruit) Tree() *Tree {
	return f.tree
}

func (f *Fruit) setImage(i *Image) {
	f.image = i
}
func (f *Fruit) setTree(t *Tree) {
	f.tree = t
}

type Strawberry struct {
	*Fruit
	id int
}

func NewStrawberry(f *Fruit) *Strawberry {
	strawberry := &Strawberry{Fruit: f}
	return strawberry
}
func (s *Strawberry) SetID(i int) {
	s.id = i
}
func (s *Strawberry) ID() int {
	return s.id
}
func (s *Strawberry) setImage(i *Image) {
	s.id = 6
	s.image = i
}

type Kiwi struct {
	*Fruit
	id string
}

func NewKiwi(f *Fruit) *Kiwi {
	kiwi := &Kiwi{Fruit: f}
	return kiwi
}
func (k *Kiwi) SetID(i string) {
	k.id = i
}

func (k *Kiwi) ID() string {
	return k.id
}
func (k *Kiwi) setImage(i *Image) {
	k.id = "abc"
	k.image = i
}
func (k *Kiwi) setTree(t *Tree) {
	k.tree = t
}

type Image struct {
	path string
}

type Tree struct {
	height int
}

func main() {
	f := NewFruit()
	f.SetImage(&Image{"kiwi1.jpg"})

	/*s := NewStrawberry(f)
	s.SetImage = s.setImage
	fmt.Println(s, s.ID(), s.Image())
	f.SetImage(&Image{"strawberry.jpg"})
	fmt.Println(s, s.ID(), s.Image())*/

	k := NewKiwi(f)
	k.SetImage = k.setImage
	k.SetTree = k.setTree
	fmt.Println(k, k.ID(), k.Image())
	f.SetImage(&Image{"kiwi2.jpg"})
	f.SetTree(&Tree{2})
	fmt.Println(k, k.ID(), k.Image(), k.Tree())
}

尽管上述代码可以工作,但我有两个问题,当父结构Fruit需要例如10个附加属性及其所需的SetXXX(*XXX)方法时:

  1. 然后,所有嵌入的结构都必须更新以反映新的父结构方法。这似乎是每个属性所需的大量必要编码。

  2. 这些嵌入的结构中的一些将不需要所有的属性方法,留下一些nil。一个很好的例子是并非所有水果都生长在树上。对于Strawberry来说,注释#2处的属性是无用的。

这两个问题都是有效的吗?我是否有办法避免它们?

附注:
该应用程序需要大量的操作吞吐量,因此理想情况下,代码应该是类型安全的和最优的,而不使用反射和过度使用类型断言(无法使每个属性为interface{})。

英文:

I have to periodically call a method of a parent struct but when called, it must update extended properties unique to the embedded struct (in my case the structs have different id data types).

The only solution I could think of was to override the a method of the parent struct so that, when the periodic method is called again, it uses the method of the embedded struct instead of the parent's original.

The code looks as follows:

package main
import (
"fmt"
)
type Fruit struct {
image *Image
tree  *Tree
SetImage func(*Image)
SetTree  func(*Tree) // #2 (always nil for Strawberry)
}
func NewFruit() *Fruit {
f := &Fruit{}
f.SetImage = f.setImage
f.SetTree = f.setTree
return f
}
func (f *Fruit) Image() *Image {
return f.image
}
func (f *Fruit) Tree() *Tree {
return f.tree
}
func (f *Fruit) setImage(i *Image) {
f.image = i
}
func (f *Fruit) setTree(t *Tree) {
f.tree = t
}
type Strawberry struct {
*Fruit
id int
}
func NewStrawberry(f *Fruit) *Strawberry {
strawberry := &Strawberry{Fruit: f}
return strawberry
}
func (s *Strawberry) SetID(i int) {
s.id = i
}
func (s *Strawberry) ID() int {
return s.id
}
func (s *Strawberry) setImage(i *Image) {
s.id = 6
s.image = i
}
type Kiwi struct {
*Fruit
id string
}
func NewKiwi(f *Fruit) *Kiwi {
kiwi := &Kiwi{Fruit: f}
return kiwi
}
func (k *Kiwi) SetID(i string) {
k.id = i
}
func (k *Kiwi) ID() string {
return k.id
}
func (k *Kiwi) setImage(i *Image) {
k.id = "abc"
k.image = i
}
func (k *Kiwi) setTree(t *Tree) {
k.tree = t
}
type Image struct {
path string
}
type Tree struct {
height int
}
func main() {
f := NewFruit()
f.SetImage(&Image{"kiwi1.jpg"})
/*s := NewStrawberry(f)
s.SetImage = s.setImage
fmt.Println(s, s.ID(), s.Image())
f.SetImage(&Image{"strawberry.jpg"})
fmt.Println(s, s.ID(), s.Image())*/
k := NewKiwi(f)
k.SetImage = k.setImage
k.SetTree = k.setTree
fmt.Println(k, k.ID(), k.Image())
f.SetImage(&Image{"kiwi2.jpg"})
f.SetTree(&Tree{2})
fmt.Println(k, k.ID(), k.Image(), k.Tree())
}

While the above code does work, I have two concerns when the parent struct Fruit needs eg. 10 additional properties with their required SetXXX(*XXX) methods:

  1. Then all the embedded structs has to be updated to reflect the new parent struct methods. Which seems like a lot of necessary coding per property.

  2. Some of these embedded structs will not need all of the property methods, leaving a few nil. A good example being not all fruit grow on trees. Leaving property at comment #2 useless for Strawberry.

Are both these concerns valid and is there a way I can avoid them?

P.S.
The application requires a lot of operational throughput so ideally the code should be type safe and optimal without the use of reflection and the overuse of type assertion (can't make every property interface{}).

答案1

得分: 2

这两个担忧都是合理的,而且有办法可以避免它们。

首先,不要试图在Go语言中编写传统的面向对象代码,而是要写出符合Go语言习惯的代码。例如,在Go语言中,设置器(Setters)和获取器(Getters)并不常见。此外,不要将嵌入(embedding)视为父子关系,改变你的思维方式。

英文:

> Are both these concerns valid and is there a way I can avoid them?

No and yes.

Just write idiomatic GO and do not try to write traditional OO in Go. E.g. Setters and Getters are not common in Go. And stop thinking of embedding as a parent/child relation.

huangapple
  • 本文由 发表于 2017年8月28日 04:46:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/45909197.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定