Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 什么是建模a的最佳方式;“超类方法实现”;在围棋中?_Ruby_Inheritance_Interface_Go - Fatal编程技术网

Ruby 什么是建模a的最佳方式;“超类方法实现”;在围棋中?

Ruby 什么是建模a的最佳方式;“超类方法实现”;在围棋中?,ruby,inheritance,interface,go,Ruby,Inheritance,Interface,Go,我希望将一个“经典OO”示例转换为Go,其中一组子类自己实现一些方法,但它们通过其超类共享一些方法的实现。我很清楚如何使用Go的接口,甚至使用过嵌入,但我不太确定要使用什么样的习惯用法来捕获这种预期行为 这是一个具体的,可能是一个非常熟悉的例子。我会用Ruby。有两种动物,狗和牛。所有动物都有一个名字,它们会说话。无论是哪种动物,你设定和获得相同结果的方式都是一样的;它们发出的声音因子类而异。现在有一个speak方法,它对所有动物都是一样的,但它将委托给子类的sound方法。这里是Ruby: c

我希望将一个“经典OO”示例转换为Go,其中一组子类自己实现一些方法,但它们通过其超类共享一些方法的实现。我很清楚如何使用Go的接口,甚至使用过嵌入,但我不太确定要使用什么样的习惯用法来捕获这种预期行为

这是一个具体的,可能是一个非常熟悉的例子。我会用Ruby。有两种动物,狗和牛。所有动物都有一个名字,它们会说话。无论是哪种动物,你设定和获得相同结果的方式都是一样的;它们发出的声音因子类而异。现在有一个
speak
方法,它对所有动物都是一样的,但它将委托给子类的
sound
方法。这里是Ruby:

class Animal
  def initialize(name); @name = name; end
  def speak; puts "#{@name} says #{sound()}"; end
end
class Dog < Animal; def sound(); "woof"; end; end
class Cow < Animal; def sound(); "mooo"; end; end
我已经能够像这样构建“动物”:

但我觉得我在这件事上完全错了。我知道我可以把
sound()
放在一个界面中,但是特定的动物是发声器,而不是真正的动物。如果
Animal
成为界面,我不能共享名称和说话代码。我意识到Go的设计者只使用接口,并没有像我们在Ruby、Python、Java等中看到的那样直接支持这个经典的OO用例,但我怀疑应该有一些习惯用法或最佳实践来模拟它。这样做的首选方式是什么

但我怀疑应该有一些习惯用法或最佳实践来模拟这种情况

不,没有

如果出现类似的情况(在实际代码中并不经常出现,但主要是在Java/Ruby/任何代码的翻译中):
名为{Name()string}
的接口和
接口发声器{Sound()}
组合到
接口动物{Named,Sounder}
并传递这些动物


再次强调:“首选方法”是在不继承的情况下重新构建解决方案。

我认为混淆可能来自使用构造实例

它们非常适合于在单行中创建复杂类型,并且正如前面的链接所建议的那样,可以减少锅炉板代码

但是,有时,代码可能会更简单,通过更明确地执行操作,可读性更强。我发现,有时利用这种机会也是如此

引用上一链接:

嵌入类型的方法是免费提供的

您没有委托子类的
sound
方法,但是“子类”
sound
的设置和获取透明地使用
Animal
sound
字段

所以我更喜欢这样做:

package main

import "fmt"

type Animal struct {
    name  string
    sound string
}

type Cow struct {
    Animal
}

type Dog struct {
    Animal
}

func (a *Animal) Speak() string {
    return fmt.Sprintf("%s", a.sound)
}

func main() {
    c := new(Cow)
    d := new(Dog)
    c.name, c.sound = "Bessie", "mooo"
    d.name, d.sound = "Sparky", "woof"
    fmt.Println(c.Speak())
    fmt.Println(d.Speak())
}
产生:

mooo

编辑:关于这个主题,有以下几点:

Go采用了一种不同寻常的面向对象编程方法,允许对任何类型(不仅仅是类)使用方法,但不允许使用任何形式的基于类型的继承(如子类化)。这意味着没有类型层次结构。这是一个有意的设计选择。尽管类型层次结构已被用于构建许多成功的软件,但我们认为该模型已被过度使用,值得后退一步

这个怎么样

package main

import (
    "fmt"
)

type Sounder interface {
    Sound() string
}

type Animal struct {
    Name    string
    Sounder Sounder
}

func (a *Animal) Speak() {
    fmt.Printf("%s says %s.\n", a.Name, a.Sounder.Sound())
}

type StringSounder string

func (f StringSounder) Sound() string {
    return string(f)
}


func main() {
    d := &Animal{"Sparky", StringSounder("woof")}
    c := &Animal{"Bessie", StringSounder("mooo")}

    d.Speak()
    c.Speak()
}

不能将非接口方法附加到接口。如果一个动物要说话,他们需要一个名字和一个声音。还可以嵌入私有类型,嵌入的是实现细节。鉴于这些见解,我认为这就是你所追求的

package farm

type Animal interface {
    Name() string
    Sound() string
}

func Speak(a Animal) string {
    return a.Name() + " says " + a.Sound()
}

type animal struct {
    name string
}

func (a *animal) Name() string {
    return a.name
}

type Cow struct {
    animal
}

func NewCow(name string) *Cow {
    return &Cow{animal{name}}
}

func (c *Cow) Sound() string {
    return "mooo"
}

type Dog struct {
    animal
}

func NewDog(name string) *Dog {
    return &Dog{animal{name}}
}

func (c *Dog) Sound() string {
    return "woof"
}
有这样一个主管道:


播放链接w/main:

回答正确,并+1给出相关的Rob Pike报价。我知道我们在Go中没有做我想做的事情(实现继承),但似乎仍然应该有一种方法来捕获业务规则,如“所有牛都说mooo”。您的解决方案很接近,可能是首选的Go方法,但是,如果有任何方法可以将动物的类型与声音联系起来,那么在解决方案中加入这一点就太好了。
package main

import (
    "fmt"
)

type Sounder interface {
    Sound() string
}

type Animal struct {
    Name    string
    Sounder Sounder
}

func (a *Animal) Speak() {
    fmt.Printf("%s says %s.\n", a.Name, a.Sounder.Sound())
}

type StringSounder string

func (f StringSounder) Sound() string {
    return string(f)
}


func main() {
    d := &Animal{"Sparky", StringSounder("woof")}
    c := &Animal{"Bessie", StringSounder("mooo")}

    d.Speak()
    c.Speak()
}
package farm

type Animal interface {
    Name() string
    Sound() string
}

func Speak(a Animal) string {
    return a.Name() + " says " + a.Sound()
}

type animal struct {
    name string
}

func (a *animal) Name() string {
    return a.name
}

type Cow struct {
    animal
}

func NewCow(name string) *Cow {
    return &Cow{animal{name}}
}

func (c *Cow) Sound() string {
    return "mooo"
}

type Dog struct {
    animal
}

func NewDog(name string) *Dog {
    return &Dog{animal{name}}
}

func (c *Dog) Sound() string {
    return "woof"
}
package main

import "fmt"
import "farm"

func main() {
    c := farm.NewCow("Betsy")
    d := farm.NewDog("Sparky")
    //"In classic OOO you'd write c.Speak()"
    fmt.Println(farm.Speak(c))
    fmt.Println(farm.Speak(d))
}