Go语言 面向对象编程 (多态)

文章目录

    • 导言
    • 多态
      • 使用接口实现多态
      • 添加新的收入来源
    • 原作者留言
    • 最后


导言

  • 原文链接: Part 28: Polymorphism - OOP in Go
  • If translation is not allowed, please leave me in the comment area and I will delete it as soon as possible.

多态

Go 中,多态的实现用到了接口。

接下来,我们来讨论下:通过接口,Go 是如何实现多态的。


使用接口实现多态

Go 语言中,接口能被隐式实现。如果 类型 定义了接口的所有方法,那该类型就实现了接口。

接口类型的变量,能存储 任意实现了该接口的对象。利用这个属性,我们就能在 Go 中实现多态。

接下来,我们将通过程序理解多态,这个程序的功能是:计算公司的总收入。这家公司的收入来源于 2 类工程,分别为 fixed billing类、 time and material类。公司的总收入 等于 这 2 类工程收入的总和。

我们先定义一个接口:

type Income interface {
       
    calculate() int
    source() string
}

从上面的程序可以看出,Income接口 包括 2 个方法。calculate方法 用于计算并返回收入,source方法 用于返回收入来源的名称。

接下来,我们来定义 FixedBillingTimeAndMaterial结构。

type FixedBilling struct {
       
    projectName string
    biddedAmount int
}

type TimeAndMaterial struct {
       
    projectName string
    noOfHours  int
    hourlyRate int
}

FixedBilling结构 拥有 2 个字段。projectName 字段 表示项目名,biddedAmount字段 表示项目的投标金额。

TimeAndMateria结构 拥有 3 个字段。projectName字段 表示项目名,noOfHours字段 表示时间,hourlyRate字段 表示每小时能获得的收入。

接下来,我们让 FixedBillingTimeAndMaterial结构 实现 Income接口。

func (fb FixedBilling) calculate() int {
       
    return fb.biddedAmount
}

func (fb FixedBilling) source() string {
       
    return fb.projectName
}

func (tm TimeAndMaterial) calculate() int {
       
    return tm.noOfHours * tm.hourlyRate
}

func (tm TimeAndMaterial) source() string {
       
    return tm.projectName
}

对于 FixedBilling类 的工程来说,收入就是投标金额。因此,该类型的 calculate方法 直接返回 biddedAmount

对于 TimeAndMaterial类 的工程来说,收入等于 noOfHourshourlyRate 的乘积。因此,该类型的 calculate方法 返回 noOfHours * hourlyRate

对于上面 2 类工程来说,source方法 都返回它们的工程名。

由于 FixedBillingTimeAndMaterial结构 具有了 Income接口 的所有方法,所以FixedBillingTimeAndMaterial结构 实现了 Income接口。

接下来,我们来写 calculateNetIncome函数,它能计算并输出公司的总收入。

func calculateNetIncome(ic []Income) {
       
    var netincome int = 0
    for _, income := range ic {
     
        fmt.Printf("Income From %s = $%d\n", income.source(), income.calculate())
        netincome += income.calculate()
    }
    fmt.Printf("Net income of organisation = $%d", netincome)
}

calculateNetIncome函数 将 []Income类型的切片 作为参数。通过遍历整个切片,调用每个元素的 calculate方法,该函数就能算得公司的总收入。遍历时,通过调用每个元素的 source方法,该函数能输出收入来源。

根据 Income接口 的具体类型,程序会调用不同的 calculatesource方法。因此,我们在 calculateNetIncome函数 中实现了多态。

在之后,如果公司又有新的收入来源。只要该收入来源实现了 Income接口,calculateNetIncome函数 就可以在未经修改的前提下,计算出公司总收入。

程序的剩余部分就是 main函数了,代码如下:

func main() {
       
    project1 := FixedBilling{
     projectName: "Project 1", biddedAmount: 5000}
    project2 := FixedBilling{
     projectName: "Project 2", biddedAmount: 10000}
    project3 := TimeAndMaterial{
     projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
    incomeStreams := []Income{
     project1, project2, project3}
    calculateNetIncome(incomeStreams)
}

main函数 中,我们创建了 3 个工程,其中 2 个类型为 FixedBilling1 个类型为 TimeAndMaterial。之后,我们将这 3 个工程,加入到了 incomeStreams切片。因为 3 个工程都实现了 Income接口,所以在将它们加入类型为 []Income 的切片时,并不会产生错误。最后,我们调用了 calculateNetIncome函数,该函数会输出多个 收入金额、收入来源。

下面就是完整的程序了:

package main

import (  
    "fmt"
)

type Income interface {
       
    calculate() int
    source() string
}

type FixedBilling struct {
       
    projectName string
    biddedAmount int
}

type TimeAndMaterial struct {
       
    projectName string
    noOfHours  int
    hourlyRate int
}

func (fb FixedBilling) calculate() int {
       
    return fb.biddedAmount
}

func (fb FixedBilling) source() string {
       
    return fb.projectName
}

func (tm TimeAndMaterial) calculate() int {
       
    return tm.noOfHours * tm.hourlyRate
}

func (tm TimeAndMaterial) source() string {
       
    return tm.projectName
}

func calculateNetIncome(ic []Income) {
       
    var netincome int = 0
    for _, income := range ic {
     
        fmt.Printf("Income From %s = $%d\n", income.source(), income.calculate())
        netincome += income.calculate()
    }
    fmt.Printf("Net income of organisation = $%d", netincome)
}

func main() {
       
    project1 := FixedBilling{
     projectName: "Project 1", biddedAmount: 5000}
    project2 := FixedBilling{
     projectName: "Project 2", biddedAmount: 10000}
    project3 := TimeAndMaterial{
     projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
    incomeStreams := []Income{
     project1, project2, project3}
    calculateNetIncome(incomeStreams)
}

运行程序,输出如下:

Income From Project 1 = $5000  
Income From Project 2 = $10000  
Income From Project 3 = $4000  
Net income of organisation = $19000  

添加新的收入来源

假如现在该公司能通过广告赚钱,广告是一种新的收入来源。

添加新的收入来源很简单,只需让它实现 Income接口。添加之后,我们不用修改 calculateNetIncome函数 的代码,该函数依旧能正常运作。这一切都归功于多态。

接下来,我们来添加新收入来源。

type Advertisement struct {
       
    adName     string
    CPC        int
    noOfClicks int
}

func (a Advertisement) calculate() int {
       
    return a.CPC * a.noOfClicks
}

func (a Advertisement) source() string {
       
    return a.adName
}

Advertisement3 个字段,分别为 adNameCPCnoOfClicks。它的收入计算公式是:CPC * noOfClicks

Advertisement 实现了 Income接口。

接下来,我们修改一下 main函数,让它包含这个新的收入来源:

func main() {
       
    project1 := FixedBilling{
     projectName: "Project 1", biddedAmount: 5000}
    project2 := FixedBilling{
     projectName: "Project 2", biddedAmount: 10000}
    project3 := TimeAndMaterial{
     projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
    bannerAd := Advertisement{
     adName: "Banner Ad", CPC: 2, noOfClicks: 500}
    popupAd := Advertisement{
     adName: "Popup Ad", CPC: 5, noOfClicks: 750}
    incomeStreams := []Income{
     project1, project2, project3, bannerAd, popupAd}
    calculateNetIncome(incomeStreams)
}

main函数 中,我们创建了 2 个类型 Advertisement 的变量,它们分别名为 bannerAdpopupAd。之后,它们被加入 incomeStreams切片。

下面就是完整程序了:

package main

import (  
    "fmt"
)

type Income interface {
       
    calculate() int
    source() string
}

type FixedBilling struct {
       
    projectName  string
    biddedAmount int
}

type TimeAndMaterial struct {
       
    projectName string
    noOfHours   int
    hourlyRate  int
}

type Advertisement struct {
       
    adName     string
    CPC        int
    noOfClicks int
}

func (fb FixedBilling) calculate() int {
       
    return fb.biddedAmount
}

func (fb FixedBilling) source() string {
       
    return fb.projectName
}

func (tm TimeAndMaterial) calculate() int {
       
    return tm.noOfHours * tm.hourlyRate
}

func (tm TimeAndMaterial) source() string {
       
    return tm.projectName
}

func (a Advertisement) calculate() int {
       
    return a.CPC * a.noOfClicks
}

func (a Advertisement) source() string {
       
    return a.adName
}
func calculateNetIncome(ic []Income) {
       
    var netincome int = 0
    for _, income := range ic {
     
        fmt.Printf("Income From %s = $%d\n", income.source(), income.calculate())
        netincome += income.calculate()
    }
    fmt.Printf("Net income of organisation = $%d", netincome)
}

func main() {
       
    project1 := FixedBilling{
     projectName: "Project 1", biddedAmount: 5000}
    project2 := FixedBilling{
     projectName: "Project 2", biddedAmount: 10000}
    project3 := TimeAndMaterial{
     projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
    bannerAd := Advertisement{
     adName: "Banner Ad", CPC: 2, noOfClicks: 500}
    popupAd := Advertisement{
     adName: "Popup Ad", CPC: 5, noOfClicks: 750}
    incomeStreams := []Income{
     project1, project2, project3, bannerAd, popupAd}
    calculateNetIncome(incomeStreams)
}

运行程序,输出如下:

Income From Project 1 = $5000  
Income From Project 2 = $10000  
Income From Project 3 = $4000  
Income From Banner Ad = $1000  
Income From Popup Ad = $3750  
Net income of organisation = $23750  

这就是多态了~

祝你天天向上~


原作者留言

优质内容来之不易,您可以通过该 链接 为我捐赠。


最后

感谢原作者的优质内容。

欢迎指出文中的任何错误。

你可能感兴趣的:(go语言,翻译,多态,go,接口,实现,结构体)