Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.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
Inheritance 处理Go中缺少继承的最佳实践_Inheritance_Go_Modeling - Fatal编程技术网

Inheritance 处理Go中缺少继承的最佳实践

Inheritance 处理Go中缺少继承的最佳实践,inheritance,go,modeling,Inheritance,Go,Modeling,我即将开始编写一个新的应用程序,我正在考虑用Go编程,我没有这方面的经验。由于Go不支持继承,我如何忠实地将这样一个域转换为Go,同时仍然遵循Go的理念 一个人有两条腿和两条胳膊,可以走路 音乐家是一个人,拥有一种乐器并能演奏它,拥有分区并能阅读它们。但是,没有人能像音乐学家一样,仅仅是一个音乐家,他拥有并演奏一种特定的乐器 小提琴手是一个拥有小提琴并能演奏小提琴的音乐家 钢琴家是一个拥有钢琴并能弹钢琴的音乐家 当小提琴家/钢琴家走在街上时,每个人都只把他看作一个人 也许我们可以像这样重新定

我即将开始编写一个新的应用程序,我正在考虑用Go编程,我没有这方面的经验。由于Go不支持继承,我如何忠实地将这样一个域转换为Go,同时仍然遵循Go的理念

  • 一个人有两条腿和两条胳膊,可以走路
  • 音乐家是一个人,拥有一种乐器并能演奏它,拥有分区并能阅读它们。但是,没有人能像音乐学家一样,仅仅是一个音乐家,他拥有并演奏一种特定的乐器
  • 小提琴手是一个拥有小提琴并能演奏小提琴的音乐家
  • 钢琴家是一个拥有钢琴并能弹钢琴的音乐家
  • 当小提琴家/钢琴家走在街上时,每个人都只把他看作一个人
也许我们可以像这样重新定义域,以删除任何“是a”关系,从而将其转换为Go:

  • 小提琴手有一个人的部分,一个音乐家的部分,一把小提琴,可以拉小提琴
  • 小提琴家/钢琴家的音乐家部分有分区,可以阅读
  • 当小提琴家/钢琴家走在街上时,每个人都只能看到他自己的部分
在转化为Go之前,对这样一个领域进行建模是最佳做法吗?当Go的作者决定在Go中排除继承时,这是Go的作者希望他们的用户拥有的思维方式吗?

这不是“Go的作者希望他们的用户拥有的思维方式”;Go没有继承性,因为它不是一种面向对象的语言,这与C没有继承性差不多

它确实有组合和接口,这就是您所描述的建模所需的全部:一个“具有”其他对象的对象应该具有该类型的字段(组合),一个“可以”执行某些操作的对象可以由接口建模


然而,如果这个问题描述的是一个实际的编程问题而不是一个隐喻,那么它可能更容易回答;当然,除非您的应用程序打算对各种音乐家的肢体和乐器进行建模。

Go还有另一个观点。您可以想到它们匹配的对象和接口。更接近你的第二句话:

小提琴手有一个人的部分,一个音乐家的部分,一把小提琴,可以拉小提琴

这是接口
音乐家
-它描述了任何有方法
播放()的人

例如,structure
小提琴家可以有这样一种方法:

type Violinist struct {}
func (v Violinist) Play() {}
钢琴家也可以演奏:

type Pianist struct {}
func (v Pianist) Play() {}
它们都匹配接口
音乐家
。因此,您可以拥有一个
music
变量,并为其分配不同的音乐家:

var musician Musician
musician = Violinist{}
musician.Play()
musician = Pianist{}
musician.Play()
看看同一个变量是如何变化的,这是巴哈维奥。这和多形性一样,不是以面向对象的方式,而是以面向对象的方式

当小提琴家/钢琴家走在街上时,每个人都只能看到他自己的部分

同样,我们可以定义一个
步行者
界面-可以在街道上行走并有适当方法的人:

type Walker interface {
    Walk()
}
这有点像鸭子打字:在我们的生活中,如果一个人能演奏,就可以带他去合奏。在围棋术语中,如果一个人有方法
Play()
,则可以将其分配给音乐家类型变量

接下来,您可以制作一个组合接口,嵌入这两个接口:

type WalkingMusician interface {
    Musician
    Walker
}
这描述了一个人可以在一瞬间玩耍和行走

var walkingMusician WalkingMusician
walkingMusician = walkingViolinist
walkingMusician.Walk()
walkingMusician.Play()

组合和接口将扁平化使用继承创建的类型层次结构。它并没有被排除在外,它被认为是不好的,因为它增加了无用的复杂性。不管它值多少钱,这可能会给你更多的思考。这个问题没有简明的答案。这只是一种不同的编程范式。如果你想使用它,你需要学习它。没有任何公式表明OOP是一边来的,而干净的Go解决方案是另一边来的。在我尝试解决实际编程问题之前,我会制作一个类似上面描述的伪应用程序,看看如何在Go中建模,以及我是否能接受Go哲学。我认为,一个人首先需要了解一门语言的是作者的观点。如果没有这一点,我将永远反对Go,试图找到解决语言局限性的方法。如果Go没有继承,那可能是因为这个概念不符合作者的愿景,他们正在考虑另一种优雅的方式来实现通过继承可以实现的目标。这就是我在这一点上试图弄明白的。正如你在尤金·利希茨基的回答和我下面的评论中所看到的,这个比喻对我来说是一个正确的例子,可以让我开始理解围棋的基本知识。非常感谢你的回答!因此,当我们期望两种类型具有相同的方法,但实现方式不同时,我们使用接口(比如小提琴手和钢琴家都可以演奏,但演奏小提琴与演奏钢琴不同)。但是,如果两种类型应该有相同的方法,对两种类型都做相同的事情(例如,小提琴手和钢琴家读取分区是相同的),那么我们应该使用组合:小提琴手和钢琴家都有一个音乐家部分,这个音乐家部分可以读取分区。是吗?我刚刚扩展了您的示例,添加了一个具有ReadPartition方法的Solfege结构和一个WalkingPianist结构,该结构可以调用Solfege结构的ReadPartition方法。请参阅:。多亏了你的帮助,我相信我现在明白了。然后,我将把你的答案标记为解决方案。
var walkingMusician WalkingMusician
walkingMusician = walkingViolinist
walkingMusician.Walk()
walkingMusician.Play()