I've noticed how hard it is to let go of the OOP style programming I've used in Java and PHP over the last 10 years or so. I'm giving golang a go (pun intended) since a few weeks, but I'm trying to feel natural around the composition over inheritance principle golang has.
How would I define a useful interface to make sure all these structs can fulfill it? I've tried to come up with a useful example that does not involve dogs, humans or weird constructs of vehicles...
package main
type Store struct {
name string
phone string
}
type HardwareStore struct{ Store }
type FoodStore struct{ Store }
type OnlineStore struct {
Store
url string
}
I think it might be because I base my thinking around their state/data and not their behaviour, I'm struggling a bit.
The obvious first choice, without an interface, would probably be this (simplified), which of course fails:
s := Store{}
h := HardwareStore{}
f := FoodStore{}
o := OnlineStore{}
stores := []Store{s, h, f, o}
I think below is what you're after. Sorry for ugly names, but I had to make them standout to make a point. And keep in mind there are no virtual functions in go, even though example below sort of simulates one.
package main
import "fmt"
type StoreInterface interface {
getName() string
setName(string)
getPhone() string
setPhone(string)
}
type Store struct {
name string
phone string
}
func (store *Store) getName() string {
return store.name;
}
func (store *Store) setName(newName string){
store.name = newName;
}
func (store *Store) getPhone() string {
return store.phone;
}
func (store *Store) setPhone(newPhone string){
store.phone = newPhone;
}
type HardwareStore struct{ Store }
type FoodStore struct{ Store }
type OnlineStore struct {
Store
url string
}
func (os *OnlineStore) getName() string{
return fmt.Sprintf("%v(%v)", os.name, os.url)
}
func main() {
s := Store{name:"s", phone:"111"}
h := HardwareStore{Store{name:"h", phone:"222"}}
f := FoodStore{Store{name:"f", phone:"333"}}
o := OnlineStore{Store:Store{name:"o", phone:"444"}, url:"http://test.com"}
fmt.Println ("Printout 1")
stores := []*Store{&s, &h.Store, &f.Store, &o.Store}
for _, s := range stores {
fmt.Printf("\t%v: %v
", s.name, s.phone);
}
fmt.Println ("Printout 2")
stores2 := []StoreInterface{&s, &h, &f, &o}
for _, s := range stores2 {
fmt.Printf("\t%v: %v
", s.getName(), s.getPhone());
}
}
Still, it goes without saying that you need to change your mindset from inheritance to functions, data structures and behavior. It's hard to break old habits (I come from many years of OOP too). But when in Rome you should think like Romans do :o) Otherwise you gonna be missing on some potential of the language.