<p>I've read mixed opinions about getters and setters in OOP. I couldn't find much go-specific information so I'm turing to you, <a href="/r/golang">/r/golang</a>.</p>
<p>On one hand, I don't want to have to write 2 methods for every field in a struct if I have to use getters and setters. It is much less work to just create the struct and then access the fields like normal.</p>
<p>On the other hand, I want inheritance. I understand how I can incorporate field inheritance with structs, but I want functions to be able to take a struct object and accept structs that inherit fields from the parameter struct. Here is an example of what I want to do:</p>
<pre><code>type Entity struct {
Id uint64
Age uint64
}
type Human struct {
*Entity
Name string
}
func PrintAge(entity Entity) {
fmt.Println(entity.Age)
}
func main() {
entity := Entity{0, 20}
person := Person{&Entity{1, 10}, "ojbway"}
PrintAge(entity)
PrintAge(person)
}
</code></pre>
<p>Is there really no simple way of doing this without using a combination of an interface and getter/setter functions? I have a couple of solutions but they aren't super easy for me in the long run (adding more classes is more work than without doing this).</p>
<p>I guess I just want your thoughts on this. Thanks! :)</p>
<hr/>**评论:**<br/><br/>Ploobers: <pre><p>This is untested, but should work. We use this pattern all throughout our codebase.</p>
<pre><code>type Entity struct {
ID uint64
Age uint64
}
type Human struct {
Entity
Name string
}
func (e Entity) PrintAge() {
fmt.Println(e.Age)
}
func main() {
entity := Entity{0, 20}
person := Person{Entity{1, 10}, "ojbway"}
entity.PrintAge()
person.PrintAge()
}
</code></pre>
<p>PS. I capitalized Id per Go standards</p></pre>ojbway: <pre><p>If we treat methods like fields, then this is just another form of field inheritance. I'm talking about in the cases where I can't program a method and need a function (e.g. my function takes 2 parameters of struct types that are "superclasses" of something else I want to pass).</p>
<p>The best solution that I could come up with was to have an interface that returned a pointer to the desired field. That way you could access and set something. For example:</p>
<pre><code>type PersonInterface interface {
ID() *uint64
Name() *string
}
type Person struct {
id uint64
name string // private fields
}
func (person *Person) ID() *uint64 { return &person.id }
func (person *Person) Name() *string { return &person.name }
func main() {
person := &Person{0, "bob"}
fmt.Println(*person.ID()) // 0
*person.ID() = 20
fmt.Println(*person.ID()) // 20
}
</code></pre>
<p>I did test this and it does in fact work. This way I only have 1 function for each field. Also I am able to write functions that take an argument of type PersonInterface, and then sub-interfaces of PersonInterface will also work.</p>
<p>The problem is that I have to remember that when dealing with these kinds of objects, I am dealing with pointers. I'm the type of person who will forget that and screw everything up.</p>
<p>Is there no way for us to do the same thing with structs, and have structs inherit structs and guarantee that a value (even a zero-value) is present for the given field?</p>
<p>edit: formatting</p></pre>Ploobers: <pre><p>In my experience, I ended up using Getters and Setters early on using Go, but I don't think they exist anywhere in my code now. I didn't specifically try to remove them, but as my coding style evolved, they became unnecessary.</p>
<p>For all of my CRUD operations, I have some standard fields in a crud.Info struct, similar to your Entity object. I embed that in all of my other structs, like Client, Campaign, Dashboard, etc. That allows me to have a sort of reverse inheritance, just like my code sample works. </p>
<p>When I need to perform functions on that, I use crud.Info as the parameter which gives me access to all its fields and functions without getters and setters.</p></pre>djherbis: <pre><p>Whenever I want to simplify something in Go, I look for a good interface. In this case, you want an easy way to access the "Entity" fields of a struct, regardless of the struct. Rather than exposing individual fields of Entity, just expose the whole entity object via an interface like so:</p>
<p><a href="http://play.golang.org/p/ESX9S_Hpin">http://play.golang.org/p/ESX9S_Hpin</a></p>
<p>Here's an extended version with three different approaches for PrintAge based on the same idea but with differently typed Args.
<a href="http://play.golang.org/p/8rwry0PZRj">http://play.golang.org/p/8rwry0PZRj</a></p></pre>kpmy: <pre><p><a href="https://gist.github.com/kpmy/ba65960a40e41f004fbd" rel="nofollow">https://gist.github.com/kpmy/ba65960a40e41f004fbd</a> no Set/Get</p></pre>jerf: <pre><p>Generally speaking the answer is no different in Go than it is in any other language. Getters are a code smell and setters are an <em>enormous</em> code smell. You need to concentrate on what you want the object to <em>do</em>, not what the object <em>is</em>. Sometimes I end up with something that looks like a "getter" in my interfaces, but really it's just a case where it so happens that what I want to "do" is get something like a name or identifier or something, and there's no further meaning, but it's still conceptually not a "getter", it's a <em>question</em> I'm asking the object that happens to have a simple answer.</p>
<p>Inheritance is not a thing in Go. Your example is almost too simple to work with, but what's going on here is that you have:</p>
<pre><code>type HasAge interface {
Age() uint64
}
</code></pre>
<p>And that's it. That's the fundamental thing going on here. You have a set of objects that you wish to ask about their age. It is an <em>implementation detail</em> that it so happens that many of the objects can have their "age" code factored out into an "Age" object:</p>
<pre><code>type Age uint64
func (a Age) Age() uint64 {
return uint64(Age)
}
type Human struct {
....
Age
}
type NotHuman struct {
....
Age
}
</code></pre>
<p>but this is not "inheritance". It's just a convenient refactoring.</p>
<p>Basically, that's how you should approach Go OO design. Start with the thing using the objects. Figure out what methods it wants to call; there's always a set of such things. Pull that into an interface. Write a couple of implementations of the interface. If it so happens that some chunk of the interface can be cleanly factored into a subordinate object that can be <em>composed</em> in (key word here, not "inherited"), great, go ahead. If not, no stress, no problem.</p>
<p>If you find yourself in a chunk of code that is "getting" and "setting", step up a level (probably literally a block in the code), and see if you can move this logic into the interface itself. Again, your example code is too small here to provide a useful demonstration.</p>
<p>In rare cases you may actually want a true "inheritance" hierarchy. In that case you'll have to do it manually, analogously to how languages that prefer to syntactically privilege inheritance require manual work to do what Go does automatically for composition. I haven't hit one of these yet, but I could name some cases where I'd consider it. But in general, you'll find composition takes you quite a bit further than your inheritance-trained mental models are telling you. If you aren't doing "some sort of UI widget hierarchy", you probably don't need inheritance.</p></pre>egonelbre: <pre><p>That example really doesn't make sense to me. Is there a real-world case that you are looking to solve. Basically, I probably wouldn't create such model, but I can't suggest anything better since the actual problem is missing.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传