Inheritance 在golang中定义接口时如何思考?

Inheritance 在golang中定义接口时如何思考?,inheritance,go,polymorphism,Inheritance,Go,Polymorphism,我注意到,在过去10年左右的时间里,我在Java和PHP中使用的OOP风格编程很难摆脱。几周后我开始尝试golang(双关语),但我试着让golang在继承原则的基础上感受到构图的自然性 我如何定义一个有用的接口来确保所有这些结构都能实现它?我试图想出一个有用的例子,不涉及狗、人或奇怪的交通工具构造 package main type Store struct { name string phone string } type HardwareStore struct{ Store

我注意到,在过去10年左右的时间里,我在Java和PHP中使用的OOP风格编程很难摆脱。几周后我开始尝试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}

我想下面就是你想要的。对不起,我的名字很难听,但我必须让它们脱颖而出才能说明问题。请记住,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());
    }
 }

不过,不用说,您需要将思维方式从继承转变为函数、数据结构和行为。很难改掉旧习惯(我也是多年的OOP爱好者)。但在罗马的时候,你应该像罗马人一样思考:o)否则你将失去语言的某些潜力

这听起来仍然像是你在尝试继承,这在围棋中不会很好地发挥作用。您是否有一个具体的问题要解决?是的,它围绕着根据用户类型具有不同属性的用户,我试图避开继承,以惯用的围棋来解决。通常,当您离开基于继承的OOP时,您可以“反转”逻辑。与其说用户属于不同的“类型”,不如说用户类型具有区别于它们的属性。您还可以基于行为定义所有内容,只需定义返回您感兴趣的字段的方法,并使用方法集定义接口。用人为的例子很难说哪一个最适合你正在研究的问题。如何使用界面?解耦代码。看见“动态”调用一个方法。看见访问围棋包。看见给变量赋值。请看。我一直在我的go编程中避免定义getter和setter,因为从惯用的角度来看,这感觉不正确,但也许这是唯一的出路?如果只是为了访问,为什么不公开变量的大写字母?@Patrick您检查了“Printout 2”的输出了吗?并将其与“打印输出1”进行比较?我在示例中只使用了getter和setter,因为代码中没有更有用的建议。这段代码实际上演示了如何从OOP模拟继承和多态性。显然,您不需要一个接口来简单地访问结构字段。请参见“打印输出1”。@Patrick只需再次查看getName(),以及它如何根据对象的实际类型在打印输出2中生成不同的输出,即使它们都被假定为“向下转换”到StoreInterface。忽略方法名称-它与所示的概念无关。感谢所有的输入。我最终以一种非常相似的方式实现了它。