教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Go 面向对象编程(译)

Go 面向对象编程(译)

发布时间:2022-01-07   编辑:jiaochengji.com
教程集为您提供Go 面向对象编程(译)等资源,欢迎您收藏本站,我们将为您提供最新的Go 面向对象编程(译)资源
<blockquote>

『就要学习 Go 语言』系列 -- 第 26 篇分享好文

</blockquote>

今天接着给大家分享关于 Go 面向对象的好文。原文作者是 William Kennedy,《Go 语言实战》作者,博客 www.ardanlabs.com/blog/ 的维护者。大部分中国的 Gopher 都是通过这个博客认识了这位 Go 大神。

有些与知识点无关的语句,翻译过来有点拗口,大家一眼带过。但与知识点相关的,都会尽量忠于原文。另外,文章做了简单的排版,方便阅读。翻译水平有限,有误的地方,请大家在下方留言指正。

<h3 class="heading" data-id="heading-0">基础</h3>

今天有人在论坛上问我一个问题,如何在不通过嵌入的情况下而获得继承的优点。重要的是,每个人都应该考虑 Go 语言,而不是他们留下的语言。我不能告诉你我从早期的 Go 实现中删除了多少代码,因为这是不必要的。语言设计师有多年的经验和知识,正在帮助创建一种快速、精简且编写代码非常有趣的语言。

我认为 Go 是一门轻量级的面向对象编程语言。是的,它具有封装和类型成员函数,但它缺乏继承,因此缺乏传统的多态性。对我来说,除非想实现多态性,否则继承是无用的。通过在 Go 中实现接口的方式,不需要继承。Go采用 OOP 中最好的部分,而忽略了其他部分,为我们提供了一种编写多态代码的更好方法。

下面是 Go 中的 OOP 快速概览。先从这三个结构体开始。

<pre><code class="lang-hljs go copyable" lang="go hljs"><span class="hljs-keyword">type</span> Animal <span class="hljs-keyword">struct</span> { Name <span class="hljs-keyword">string</span> mean <span class="hljs-keyword">bool</span> } <span class="hljs-keyword">type</span> Cat <span class="hljs-keyword">struct</span> { Basics Animal MeowStrength <span class="hljs-keyword">int</span> } <span class="hljs-keyword">type</span> Dog <span class="hljs-keyword">struct</span> { Animal BarkStrength <span class="hljs-keyword">int</span> } <span class="copy-code-btn">复制代码</span></code></code></pre>

在任何关于 OOP 的示例中,你都可能看到上面三个结构体。一个基础结构体 Animal 和基于 Animal 声明的结构体 Cat 和 Dog。结构体 Animal 拥有所有动物共同的属性。

除了成员 mean,其他所有成员都是公共的、可被外部访问的。结构体 Animal 的 mean 成员以小写字母开头。在 Go 中,变量、结构体、成员、函数等的第一个字母的大小写决定了访问权限。大写字母开头表示公共的,可供外部调用;小写字母开头表示私有的,外部不能调用。

由于 Go 里没有继承,所以组合是你唯一的选择。结构体 Cat 的一个成员是 Basics,类型是 Animal。而结构体 Dog 通过匿名的方式嵌入了结构体 Animal。哪种实现方式更好取决于你,我会展示这两种实现方式。

给结构体 Cat 和 Dog 创建各自的方法:

<pre><code class="lang-hljs go copyable" lang="go hljs"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(dog *Dog)</span> <span class="hljs-title">MakeNoise</span><span class="hljs-params">()</span></span> { barkStrength := dog.BarkStrength <span class="hljs-keyword">if</span> dog.mean == <span class="hljs-literal">true</span> { barkStrength = barkStrength * <span class="hljs-number">5</span> } <span class="hljs-keyword">for</span> bark := <span class="hljs-number">0</span>; bark < barkStrength; bark { fmt.Printf(<span class="hljs-string">"BARK "</span>) } fmt.Println(<span class="hljs-string">""</span>) } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cat *Cat)</span> <span class="hljs-title">MakeNoise</span><span class="hljs-params">()</span></span> { meowStrength := cat.MeowStrength <span class="hljs-keyword">if</span> cat.Basics.mean == <span class="hljs-literal">true</span> { meowStrength = meowStrength * <span class="hljs-number">5</span> } <span class="hljs-keyword">for</span> meow := <span class="hljs-number">0</span>; meow < meowStrength; meow { fmt.Printf(<span class="hljs-string">"MEOW "</span>) } fmt.Println(<span class="hljs-string">""</span>) } <span class="copy-code-btn">复制代码</span></code></code></pre>

使用指针接收者实现各自的方法 MakeNoise()。这两个方法做同样的事情,如果 mean 为 true 话,每个动物会基于吠或喵的强度,用各自的母语说话。很无聊,但它展示了如何访问引用的对象。

我们可以使用 Dog 引用直接调用结构体 Animal 的成员,而 Cat 必须通过成员 Basics 访问到 Animal 的成员。

到目前为止,我们已经讨论了封装、组合、访问规范和成员函数,剩下的就是如何创建多态行为。

通过接口实现多态:

<pre><code class="lang-hljs go copyable" lang="go hljs"><span class="hljs-keyword">type</span> AnimalSounder <span class="hljs-keyword">interface</span> { MakeNoise() } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">MakeSomeNoise</span><span class="hljs-params">(animalSounder AnimalSounder)</span></span> { animalSounder.MakeNoise() } <span class="copy-code-btn">复制代码</span></code></code></pre>

上面的代码,我们添加一个接口 AnimalSounder 和一个公共函数 MakeSomeNoise(),该函数接受接口类型的值。实际上,该函数将引用实现此接口的类型的值。接口不是可以实例化的类型,是行为声明,其他类型可以去实现接口声明的行为。

在 Go 中,通过方法实现接口的任何类型都表示接口类型。在我们的例子中,结构体 Dog 和 Cat 都通过指针接收者实现了接口 AnimalSounder,所以它们都可以看成是 AnimalSounder 类型。

这意味着,Dog 和 Cat 的指针可以作为参数传递给函数 MakeSomeNoise()。MakeSomeNoise() 函数通过 AnimalSounder 接口实现多态行为。

查看完整代码

<h3 class="heading" data-id="heading-1">进阶</h3>

如果你想减少 Cat 和 Dog 的 MakeNoise() 方法中的代码重复,可以为 Animal 类型创建一个方法来处理:

<pre><code class="lang-hljs go copyable" lang="go hljs"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(animal *Animal)</span> <span class="hljs-title">PerformNoise</span><span class="hljs-params">(strength <span class="hljs-keyword">int</span>, sound <span class="hljs-keyword">string</span>)</span></span> { <span class="hljs-keyword">if</span> animal.mean == <span class="hljs-literal">true</span> { strength = strength * <span class="hljs-number">5</span> } <span class="hljs-keyword">for</span> voice := <span class="hljs-number">0</span>; voice < strength; voice { fmt.Printf(<span class="hljs-string">"%s "</span>, sound) } fmt.Println(<span class="hljs-string">""</span>) } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(dog *Dog)</span> <span class="hljs-title">MakeNoise</span><span class="hljs-params">()</span></span> { dog.PerformNoise(dog.BarkStrength, <span class="hljs-string">"BARK"</span>) } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cat *Cat)</span> <span class="hljs-title">MakeNoise</span><span class="hljs-params">()</span></span> { cat.Basics.PerformNoise(cat.MeowStrength, <span class="hljs-string">"MEOW"</span>) } <span class="copy-code-btn">复制代码</span></code></code></pre>

现在 Animal 类型有一个处理 noise 的方法,可以被其外部类型调用,例如 Dog、Cat 类型。还有一个好处,我们不需要将 mean 成员作为参数传递,因为它就属于 Animal 结构体。 下面是完整代码:

<pre><code class="lang-hljs go copyable" lang="go hljs"><span class="hljs-keyword">package</span> main <span class="hljs-keyword">import</span> ( <span class="hljs-string">"fmt"</span> ) <span class="hljs-keyword">type</span> Animal <span class="hljs-keyword">struct</span> { Name <span class="hljs-keyword">string</span> mean <span class="hljs-keyword">bool</span> } <span class="hljs-keyword">type</span> AnimalSounder <span class="hljs-keyword">interface</span> { MakeNoise() } <span class="hljs-keyword">type</span> Dog <span class="hljs-keyword">struct</span> { Animal BarkStrength <span class="hljs-keyword">int</span> } <span class="hljs-keyword">type</span> Cat <span class="hljs-keyword">struct</span> { Basics Animal MeowStrength <span class="hljs-keyword">int</span> } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> { myDog := &Dog{ Animal{ <span class="hljs-string">"Rover"</span>, <span class="hljs-comment">// Name</span> <span class="hljs-literal">false</span>, <span class="hljs-comment">// mean</span> }, <span class="hljs-number">2</span>, <span class="hljs-comment">// BarkStrength</span> } myCat := &Cat{ Basics: Animal{ Name: <span class="hljs-string">"Julius"</span>, mean: <span class="hljs-literal">true</span>, }, MeowStrength: <span class="hljs-number">3</span>, } MakeSomeNoise(myDog) MakeSomeNoise(myCat) } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(animal *Animal)</span> <span class="hljs-title">PerformNoise</span><span class="hljs-params">(strength <span class="hljs-keyword">int</span>, sound <span class="hljs-keyword">string</span>)</span></span> { <span class="hljs-keyword">if</span> animal.mean == <span class="hljs-literal">true</span> { strength = strength * <span class="hljs-number">5</span> } <span class="hljs-keyword">for</span> voice := <span class="hljs-number">0</span>; voice < strength; voice { fmt.Printf(<span class="hljs-string">"%s "</span>, sound) } fmt.Println(<span class="hljs-string">""</span>) } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(dog *Dog)</span> <span class="hljs-title">MakeNoise</span><span class="hljs-params">()</span></span> { dog.PerformNoise(dog.BarkStrength, <span class="hljs-string">"BARK"</span>) } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cat *Cat)</span> <span class="hljs-title">MakeNoise</span><span class="hljs-params">()</span></span> { cat.Basics.PerformNoise(cat.MeowStrength, <span class="hljs-string">"MEOW"</span>) } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">MakeSomeNoise</span><span class="hljs-params">(animalSounder AnimalSounder)</span></span> { animalSounder.MakeNoise() } <span class="copy-code-btn">复制代码</span></code></code></pre>

输出:

<pre><code class="lang-hljs go copyable" lang="go hljs">BARK BARK MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW MEOW <span class="copy-code-btn">复制代码</span></code></code></pre><h3 class="heading" data-id="heading-2">结构体中嵌入接口</h3>

有人在后台给出了一个在结构体中嵌入接口的例子:

<pre><code class="lang-hljs go copyable" lang="go hljs"><span class="hljs-keyword">package</span> main <span class="hljs-keyword">import</span> ( <span class="hljs-string">"fmt"</span> ) <span class="hljs-keyword">type</span> HornSounder <span class="hljs-keyword">interface</span> { SoundHorn() } <span class="hljs-keyword">type</span> Vehicle <span class="hljs-keyword">struct</span> { List [<span class="hljs-number">2</span>]HornSounder } <span class="hljs-keyword">type</span> Car <span class="hljs-keyword">struct</span> { Sound <span class="hljs-keyword">string</span> } <span class="hljs-keyword">type</span> Bike <span class="hljs-keyword">struct</span> { Sound <span class="hljs-keyword">string</span> } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> { vehicle := <span class="hljs-built_in">new</span>(Vehicle) vehicle.List[<span class="hljs-number">0</span>] = &Car{<span class="hljs-string">"BEEP"</span>} vehicle.List[<span class="hljs-number">1</span>] = &Bike{<span class="hljs-string">"RING"</span>} <span class="hljs-keyword">for</span> _, hornSounder := <span class="hljs-keyword">range</span> vehicle.List { hornSounder.SoundHorn() <span class="hljs-comment">// PressHorn(hornSounder) 这种方式也可以</span> } } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(car *Car)</span> <span class="hljs-title">SoundHorn</span><span class="hljs-params">()</span></span> { fmt.Println(car.Sound) } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(bike *Bike)</span> <span class="hljs-title">SoundHorn</span><span class="hljs-params">()</span></span> { fmt.Println(bike.Sound) } <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">PressHorn</span><span class="hljs-params">(hornSounder HornSounder)</span></span> { hornSounder.SoundHorn() } <span class="copy-code-btn">复制代码</span></code></code></pre>

在这个例子中,结构体 Vehicle 维护了一个实现 HornSounder 接口的值列表。在 main 函数中创建了变量 vehicle,并存储了 Car 类型变量和 Bike 变量的指针。这种赋值操作是可以的,因为 Car 和 Bike 都实现了接口。接着就是要一个简单的 loop 操作,循环调用 SoundHorn() 方法。

在你的应用程序中,任何你需要实现面向对象的东西在 Go 语言中都有。正如我之前所说的,Go 采用了 OOP 中最好的部分,省略了其他部分,为我们提供了编写多态代码的更好方法。

与主题相关联的几篇文章:
1.Methods, Interfaces and Embedded Types in Go
2.How Packages Work in Go
3.Singleton Design Pattern in Go

希望这几个简单的例子能对你的 Go 编程有帮助!

推荐阅读:
1.教女朋友写方法(续)
2.Go 面向对象式编程


到此这篇关于“Go 面向对象编程(译)”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
龙芯平台构建Go语言环境指南
Go语言学习3----Go语言特色
关于Golang的介绍
go语言和python哪个难
Go语言的特性
Go语言发展历史、核心、特性及学习路线
Golang 介绍
Go Base
Go 语言到底适合干什么?
go 语言学习历程

[关闭]
~ ~