How to think when defining interfaces in golang?

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

How to think when defining interfaces in golang?

问题

我注意到放弃我在过去10年中在Java和PHP中使用的面向对象编程(OOP)风格是多么困难。我最近几周开始尝试使用Go语言(golang),但我正在努力适应golang中的组合优于继承原则。

我该如何定义一个有用的接口,以确保所有这些结构体都能满足它?我试图想出一个有用的示例,不涉及狗、人或奇怪的车辆构造...

package main

type Store struct {
	name  string
	phone string
}

type HardwareStore struct{ Store }

type FoodStore struct{ Store }

type OnlineStore struct {
	Store
	url string
}

我认为这可能是因为我以它们的状态/数据为基础进行思考,而不是它们的行为,所以我有点困惑。

显而易见的第一个选择,没有接口的话,可能是这样的(简化),当然会失败:

s := Store{}
h := HardwareStore{}
f := FoodStore{}
o := OnlineStore{}

stores := []Store{s, h, f, o}
英文:

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}

答案1

得分: 4

我认为下面是你想要的代码。对于变量名的不美观表示抱歉,但我必须使它们突出以说明一点。请记住,在Go语言中没有虚函数,尽管下面的示例有点类似。

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\n", s.name, s.phone)
    }

    fmt.Println("Printout 2")
    stores2 := []StoreInterface{&s, &h, &f, &o}
    for _, s := range stores2 {
        fmt.Printf("\t%v: %v\n", s.getName(), s.getPhone())
    }
}

然而,毋庸置疑,你需要改变思维方式,从继承转向函数、数据结构和行为。摆脱旧习惯并不容易(我也来自多年的面向对象编程)。但是,当你在罗马时,你应该像罗马人一样思考: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\n", s.name, s.phone);
}
fmt.Println ("Printout 2")
stores2 := []StoreInterface{&s, &h, &f, &o}
for _, s := range stores2 {
fmt.Printf("\t%v: %v\n", 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.

huangapple
  • 本文由 发表于 2017年1月14日 05:45:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/41643909.html
匿名

发表评论

匿名网友

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

确定