4 ms·
> With proper composition, your child objects are named, and you can choose which interfaces you want to delegate to which object. This doesn't just give you b
by rakoo 10y ago
> With proper composition, your child objects are named, and you can choose which interfaces you want to delegate to which object. This doesn't just give you better control over which functionality you wish to expose, but also avoids conflict when two member objects implement the same interface.
Oh but you can avoid that, it's part of the language, see this link:
https://golang.org/doc/effective_go.html#embedding https://golang.org/doc/effective_go.html#embedding
Typically, you can have something like this:
type lockedReader struct {
io.Reader
sync.Mutex
}
lr := lockerReader{someReader, sync.Mutex{}}
lr.Lock()
lr.Read(...)
lr.Unlock()
By default, methods will be delegated to the first field that has the method. If you want something else, you are free to override this default behavior.
- unscaled 10y agoNo they're not. io.Reader and sync.Mutex do not embed the same type and do not have conflicting methods with the same name. This is how a diamond looks like: type Base struct { Foo int32 } type Child1 struct { Base } type Child2 struct { Base } type Diamond struct { Child1 Child2 } func (c *Child1) DoSomething() { fmt.Println(c.Foo) } func (c *Child2) DoSomething() { fmt.Println(c.Foo) } func main() { c := Diamond { } c.Foo = 42 // Doesn't Compile c.Child1.Foo = 10 c.Child2.Foo = 20 c.DoSomething() // Doesn't Compile }