I'm OOP guy, recently I have to work on Golang the language that I haven't done it before. Though I already went through many articles talking about composition, I notice it's a bit tricky to use it properly on Golang
Let's say I have two examples of Golang composition, I don't know which one will be correct, and would it be different between of them? Thank you
First example
type BaseClass struct {
db *DB
}
func NewBaseClass(db *DB) *BaseClass {
return &BaseClass{db}
}
type ChildrenClass1 struct {
baseClass *BaseClass
}
func NewChildrenClass1(db *DB) *ChildrenClass1 {
baseClass := NewBaseClass(db)
return &ChildrenClass1{baseClass}
}
type ChildrenClass2 struct {
baseClass *BaseClass
}
func NewChildrenClass2(db *DB) *ChildrenClass2 {
baseClass := NewBaseClass(db)
return &ChildrenClass2{baseClass}
}
func main(){
db := NewDB()
chilrend1 := NewChildrenClass1(db)
chilrend2 := NewChildrenClass2(db)
}
Second example
type BaseClass struct {
db *DB
}
func NewBaseClass(db *DB) *BaseClass {
return &BaseClass{db}
}
type ChildrenClass1 struct {
baseClass *BaseClass
}
func NewChildrenClass1(baseClass *BaseClass) *ChildrenClass1 {
return &ChildrenClass1{baseClass}
}
type ChildrenClass2 struct {
baseClass *BaseClass
}
func NewChildrenClass2(baseClass *BaseClass) *ChildrenClass2 {
return &ChildrenClass2{baseClass}
}
func main(){
db := NewDB()
baseClass := NewBaseClass(db)
chilrend1 := NewChildrenClass1(baseClass)
chilrend2 := NewChildrenClass2(baseClass)
}
In Go you probably will not find a proper way to define composition or aggregation as you may find in many other languages that are OOP based. This is just because Go has no classes, no objects, no exceptions, and no templates.
But Go has structs. Structs are user-defined types. Struct types (with methods) serve similar purposes to classes in other languages.
Said that, let's see some common definitions and see what we can do:
Composition implies a relationship where the child cannot exist independent of the parent. Example: House (parent) and Room (child). Rooms don't exist separate to a House[1].
Aggregation, in other hand, implies a relationship where the child can exist independently of the parent. Example: Classroom (parent) and Student (child). Delete the Classroom and the Students still exist[1].
So, in aggregation and composition the "instance" "owns" an object of another type. But there is a subtle difference: Aggregation implies a relationship where the child can exist independently of the parent. Composition implies a relationship where the child cannot exist independent of the parent.
So far, that's what we know now from composition:
The child cannot exist without the parent
Composition refers to combining simpler types to make more complex ones
And of course, we mainly use it to be able to reuse code
Answer to your question:
Both looks correct but,
The first example is closer to a composition, because the child will not exist without the parent;
The second example is more like an aggregation, because if you remove the parent, the child will keep existing.
I re-wrote your code on an attempt to exemplify it:
First example re-written
package main
//Lamp struct is here to suppress the *DB that was in the original example
type Lamp struct {}
type Room struct {
Lamps *[]Lamp
}
func NewRoom(l *[]Lamp) *Room {
return &Room{l}
}
type House1 struct {
Room *Room
}
func NewHouse1(l *[]Lamp) *House1 {
r := NewRoom(l)
return &House1{r}
}
type House2 struct {
Room *Room
}
func NewHouse2(l *[]Lamp) *House2 {
r := NewRoom(l)
return &House2{r}
}
func main(){
lamps := []Lamp{}
house1 := NewHouse1(&lamps)
house2 := NewHouse2(&lamps)
}
Second example re-written:
package main
type LibraryCard struct {}
type Student struct {
LibCard *LibraryCard
}
func NewStudent(l *LibraryCard) *Student {
return &Student{l}
}
type Classroom1 struct {
Student *Student
}
func NewClassroom1(s *Student) *Classroom1 {
return &Classroom1{s}
}
type Classroom2 struct {
Student *Student
}
func NewClassroom2(s *Student) *Classroom2 {
return &Classroom2{s}
}
func main(){
lc := new(LibraryCard)
student := NewStudent(lc)
classroom1 := NewClassroom1(student)
classroom2 := NewClassroom2(student)
}
Related
I have two different interfaces (from two different packages) that I want to implement. But they conflict, like this:
type InterfaceA interface {
Init()
}
type InterfaceB interface {
Init(name string)
}
type Implementer struct {} // Wants to implement A and B
func (i Implementer) Init() {}
func (i Implementer) Init(name string) {} // Compiler complains
It says "Method redeclared". How can one struct implement both interfaces?
As already answered, this is not possible since Golang does not (and probably will not) support method overloading.
Look at Golang FAQ:
Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.
It is not possible.
In go you must have a single method signature.
You should rename one method.
The method signatures must match. If you want dependency injection I would recommend the functional option pattern. Functional options are functions that return other functions that are called in a loop in the constructor. Here is an example of how to use functional options and the basics of interfaces in go.
package main
import (
"fmt"
"strconv"
)
type SomeData struct {
data string
}
// SomeData and SomeOtherData both implement SomeInterface and SomeOtherInterface
// SomeInterface and SomeOtherInterface both implement each other.
type SomeInterface interface {
String() string
Set(data string)
}
func (s *SomeData)String() string {
return s.data
}
func (s *SomeData)Set(data string) {
s.data = data
}
// SetDataOption is a functional option that can be used to inject a constructor dep
func SetDataOption(data string) func(*SomeData) {
return func(s *SomeData) {
s.Set(data)
}
}
// NewSomeData is the constructor; it takes in 0 to many functional options and calls each one in a loop.
func NewSomeData(options ...func(s *SomeData)) SomeInterface {
s := new(SomeData)
for _, o := range options {
o(s)
}
return s
}
//********************
type SomeOtherData struct {
data string
i int
}
type SomeOtherInterface interface {
String() string
Set(data string)
}
func (s *SomeOtherData)String() string {
return s.data + " " + strconv.Itoa(s.i)
}
func (s *SomeOtherData)Set(data string) {
s.data = data
}
func SetOtherDataOption(data string) func(*SomeOtherData) {
return func(s *SomeOtherData) {
s.Set(data)
}
}
func SetOtherIntOption(i int) func(*SomeOtherData) {
return func(s *SomeOtherData) {
s.i = i
}
}
// NewSomeOther data works just like NewSomeData only in this case, there are more options to choose from
// you can use none or any of them.
func NewSomeOtherData(options ...func(s *SomeOtherData)) SomeOtherInterface {
s := new(SomeOtherData)
for _, o := range options {
o(s)
}
return s
}
//*********************************
// HandleData accepts an interface
// Regardless of which underlying struct is in the interface, this function will handle
// either by calling the methods on the underlying struct.
func HandleData(si SomeInterface) {
fmt.Println(si) // fmt.Println calls the String() method of your struct if it has one using the Stringer interface
}
func main() {
someData := NewSomeData(SetDataOption("Optional constructor dep"))
someOtherData := NewSomeOtherData(SetOtherDataOption("Other optional constructor dep"), SetOtherIntOption(42))
HandleData(someData) // calls SomeData.String()
HandleData(someOtherData) // calls SomeOtherData.String()
someOtherData = someData // assign the first interface to the second, this works because they both implement each other.
HandleData(someOtherData) // calls SomeData.String() because there is a SomeData in the someOtherData variable.
}
this question is related to Passing struct with anonymous field in Go but different in that I am dealing with a function that handles an array of Parent items rather than just one struct, ie:
package main
import "fmt"
type Parent struct {
Dad string
}
type Child struct {
Parent
Son string
}
func myfunc(data []Parent) {
for n, _ := range data {
fmt.Printf("Dad is %s\n", data[n].Dad)
}
}
func main() {
data := make([]Child, 2)
data[0].Dad = "pappy"
data[0].Son = "sonny"
data[1].Dad = "daddy"
data[1].Son = "billy"
myfunc(data)
}
I tried to cast data to an array of Parents like myfunc([]Parent(data)) but that didnt work and obviously the solution of myfunc(data.Parent) wont work on an array.
Is there a reasonable solution to this in golang without resorting to creating a new slice or generics which are not out of beta yet?
Cheers
You cannot do this even with generics. data[n].Dad will not work.
The reasonable way to deal with it is to use an interface, but still, you have to create an interface slice for it:
type WithDad interface {
GetDad() string
}
func (p Parent) GetDad() string {return p.Dad}
func myFunc(data []WithDad) {
...
}
...
arr:=make([]WithDad,0,len(data))
for _,x:=range data {
arr=append(arr,x)
}
myFunc(arr)
The reason for this is how the type system works and how slices are passed around. The slice []Child points to an array where each entry is a Child. A function that takes []Parent expects a slice whose elements are Parent, which is a different type, so you cannot pass one for the other.
The slice []WithDad points to an array where each entry is an interface. Each such entry points to the Child or Parent entry in another slice.
Just for completeness I made a complete version of Burak Serdar code I got working (I like it when full working examples are posted for me to cut and paste later :P) ... note I deliberately return a pointer to the Parent because in practice its likely you will want to work on that complete struct and not just read 1 field.
package main
import "fmt"
type WithDad interface {
GetDad() *Parent
}
type Parent struct {
Dad string
}
func (p *Parent) GetDad() *Parent {
return p
}
type Child struct {
Parent
Son string
}
func (c *Child) GetDad() *Parent {
return &c.Parent
}
func myfunc(data []WithDad) {
for n, _ := range data {
fmt.Printf("Dad is %s\n", data[n].GetDad().Dad)
}
}
func main() {
data := make([]WithDad, 2)
data[0] = &Child{Parent: Parent{Dad: "pappy"}, Son: "sonny"}
data[1] = &Child{Parent: Parent{Dad: "daddy"}, Son: "billy"}
myfunc(data)
}
Your structure with Child being a composite of Parent and a string (which I guess contains the name) makes little sense. A child is not a parent plus their name. In fact you only have one concept, namely Person, who potentially has a parent. Please consider the following approach:
package main
import "fmt"
type Person struct {
Name string
Parent *Person
}
func myfunc(data []Person) {
for n, _ := range data {
fmt.PrintLn("My name is", n.Name)
if n.Parent != nil {
fmt.PrintLn("My dad is", n.Parent.Name)
}
}
}
func main() {
data := make([]Person, 2)
data[0].Name = "daddy"
data[1].Name = "billy"
data[1].Parent = &data[0]
myfunc(data)
}
I am new to go (golang). That is why my question may be irrelevant (or impossible to answer).
I have created two structs. Both of these embed another struct. Now I want to update a field of the embedded struct inside a function.
package main
import (
"fmt"
"reflect"
"time"
)
type Model struct {
UpdatedAt time.Time
}
type Fruit struct {
Model
label string
}
type Animal struct {
Model
label string
}
func update(v interface{}) {
reflectType := reflect.TypeOf(v)
reflectKind := reflectType.Kind()
if reflectKind == reflect.Ptr {
reflectType = reflectType.Elem()
}
m := reflect.Zero(reflectType)
fmt.Println(m)
}
func main() {
apple := &Fruit{
label: "Apple",
}
tiger := &Animal{
label: "Tiger",
}
update(apple)
update(tiger)
fmt.Println(apple)
fmt.Println(tiger)
}
I wish to implement the update function so that it will put the current time in UpdatedAt of the passed struct. But I am not able to do this.
In this case, the field of Fruit and Animal is same: label. But it will not always be. Please keep that in mind when providing your suggestions.
Any guidance would be much appreciated.
I'd avoid reflect or interface{} if you're starting to learn go. Beginners usually fall back on them like a void * crutch. Try to use concrete types or well defined interfaces.
This should get you going:
type Timestamper interface {
Update()
UpdatedTime() time.Time
}
type Model struct {
updated time.Time
}
func (m *Model) Update() { m.updated = time.Now() }
func (m *Model) UpdatedTime() time.Time { return m.updated }
type Fruit struct {
Model
label string
}
type Animal struct {
Model
label string
}
// update will work with a `Model` `Animal` or `Fruit`
// as they all implement the `Timestamper` interface`
func update(v Timestamper) {
v.Update()
}
Playground: https://play.golang.org/p/27yDVLr-zqd
Assuming you want to achieve this via reflection: first of all, you have to pass a pointer to the struct. You're now passing a copy of the struct, so any modifications done in update will be done on the copy, not on the instance you passed in. Then, you can lookup the field UpdatedAt in the interface passed in, and set it.
That said, that's probably not the best way to do this. Another way of doing this without reflection is:
func update(in *Model) {
in.UpdatedAt = time.Now()
}
func main() {
apple := &Fruit{}
update(&apple.Model)
}
Or:
func (in *Model) update() {
in.UpdatedAt = time.Now()
}
func main() {
apple := &Fruit{}
apple.update()
}
I'm trying to use builder patterns (borrowed from Java) to allow structs to implement interfaces. For example, I would ideally like this code pattern:
package main
import "fmt"
type Oner interface {
One() int
}
type Twoer interface {
Two() int
}
func main() {
s := NewObject().
WithOne(1).
Build()
_, ok := s.(Oner)
fmt.Println(ok) // Prints true
_, ok = s.(Twoer)
fmt.Println(ok) // Prints false
t := NewObject().
WithOne(1).
WithTwo(2).
Build()
_, ok = t.(Oner)
fmt.Println(ok) // Prints true
_, ok = t.(Twoer)
fmt.Println(ok) // Prints true
}
As you could see, the definition of the builder determines what interfaces s and t implement.
How would one write the function definition of the builder NewObject() so the Build() method returns a struct which can (possibly) implement a Oner and Twoer?
Edit:
Here's some clarification on how it's going to be used. I'm constructing a library barring certain structs from being passed into functions if they violate the type safety. For example:
type Oner interface {
One() int
}
type OneAndTwoer interface {
Oner
Two() int
}
type Library interface {
DoSomethingWithOner(Oner)
DoSomethingWithOneAndTwoer(Twoer)
}
Though we can define a function which always constructs a OneAndTwoer, my constraints are whenever we construct a OneAndTwoer, this takes a lot longer time than just constructing a Oner
func NewOneAndTwoer() OneAndTwoer {
// Do some really really complicated logic which takes a lot of time
}
func NewOner() Oner {
// Do simple logic
}
You could imagine how if we have a Threer, Fourer, etc, this becomes extremely unwieldly, and we have to construct constructors for all possible permutations of attributes.
This is where builder patterns come in handy. Assuming the calculations for One, Two, etc are independent of each other, we can pick and choose which interface we want to create.
Here is a way to do it, though it feels very clunky.
package main
import (
"fmt"
)
type FieldOner interface {
FieldOne() int
}
type FieldTwoer interface {
FieldTwo() int
}
Set up structs One and Two implementing FieldOner and FieldTwoer respectively.
type One struct {
one int
}
func (f One) FieldOne() int {
return f.one
}
type Two struct {
two int
}
func (f Two) FieldTwo() int {
return f.two
}
Create the FieldBuilder which can store both values and whether it has been given each value, plus WithFieldOne and WithFieldTwo.
type FieldBuilder struct {
one int
has_one bool
two int
has_two bool
}
func NewObject() FieldBuilder {
return FieldBuilder{ has_one: false, has_two: false }
}
func (f FieldBuilder) WithFieldOne(one int) FieldBuilder {
f.one = one
f.has_one = true
return f
}
func (f FieldBuilder) WithFieldTwo(two int) FieldBuilder {
f.two = two
f.has_two = true
return f
}
Build might return One, Two, or a combination of One and Two. Since it can return multiple things which have nothing in common between them (a red flag) it returns an interface{}.
func (f FieldBuilder) Build() interface{} {
switch {
case f.has_one && f.has_two:
return struct {
One
Two
}{
One{one: f.one}, Two{two: f.two},
}
case f.has_one:
return One{ one: f.one }
case f.has_two:
return Two{ two: f.two }
}
panic("Should never be here")
}
Because Build returns an interface{} it's necessary to typecast the result in order to actually use it possibly defeating the whole point of the exercise.
func main() {
s := NewObject().
WithFieldOne(1).
Build()
s1, ok := s.(FieldOner)
fmt.Println(s1.FieldOne())
_, ok = s.(FieldTwoer)
fmt.Println(ok) // Prints false
t := NewObject().
WithFieldOne(1).
WithFieldTwo(2).
Build()
t1, ok := t.(FieldOner)
fmt.Println(t1.FieldOne())
t2, ok := t.(FieldTwoer)
fmt.Println(t2.FieldTwo())
}
This does not scale particularly well. Two interfaces require three cases. Three will require six. Four will require ten. Five will need fifteen...
Below I have an example of one structure which embeds another. I'm trying to figure out how to pass the more specific structure pointer to be stored in a less specific one. You can think of it as a collection. Wrapping in an interface doesn't seem to work, as doing so would make a copy, which isn't valid for structs with locks. Ideas?
package stackoverflow
import "sync"
type CoolerThingWithLock struct {
fancyStuff string
ThingWithLock
}
func NewCoolerThingWithLock() *CoolerThingWithLock {
coolerThingWithLock := &CoolerThingWithLock{}
coolerThingWithLock.InitThingWithLock()
return coolerThingWithLock
}
type ThingWithLock struct {
value int
lock sync.Mutex
children []*ThingWithLock
}
func (thingWithLock *ThingWithLock) InitThingWithLock() {
thingWithLock.children = make([]*ThingWithLock, 0)
}
func NewThingWithLock() *ThingWithLock {
newThingWithLock := &ThingWithLock{}
newThingWithLock.InitThingWithLock()
return newThingWithLock
}
func (thingWithLock *ThingWithLock) AddChild(newChild *ThingWithLock) {
thingWithLock.children = append(thingWithLock.children, newChild)
}
func (thingWithLock *ThingWithLock) SetValue(newValue int) {
thingWithLock.lock.Lock()
defer thingWithLock.lock.Unlock()
thingWithLock.value = newValue
for _, child := range thingWithLock.children {
child.SetValue(newValue)
}
}
func main() {
thingOne := NewThingWithLock()
thingTwo := NewCoolerThingWithLock()
thingOne.AddChild(thingTwo)
thingOne.SetValue(42)
}
Error: cannot use thingTwo (type *CoolerThingWithLock) as type
*ThingWithLock in argument to thingOne.AddChild
It's impossible to store the wrapping type in []*ThignWithLock since go has no notion of structural subtyping.
Your assertion that an interface will result in copying is incorrect, and you can get the desired effect by doing:
type InterfaceOfThingThatParticipatesInAHierarchy interface {
AddChild(InterfaceOfThingThatParticipatesInAHierarchy)
SetValue(int)
}
type ThingWithLock struct {
...
children []InterfaceOfThingThatParticipatesInAHierarchy
}
func (thingWithLock *ThingWithLock) AddChild(newChild InterfaceOfThingThatParticipatesInAHierarchy) { ... }
As long as the interface is implemented on a *ThingWithLock and not ThingWithLock, there will be no copying of the receiver struct itself, only the pointer to the struct will be copied on the stack.