golang教程之多态性-Go面向对象

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wyy626562203/article/details/83411447

多态性-Go面向对象

https://golangbot.com/polymorphism/

Go中的多态性是在接口的帮助下实现的。正如我们已经讨论过的,接口可以在Go中隐式实现。如果类型为接口中声明的所有方法提供定义,则类型实现接口。让我们看看在接口的帮助下如何在Go中实现多态性。

使用接口的多态性

任何定义接口所有方法的类型都被称为隐式实现该接口。

接口类型的变量可以包含实现接口的任何值。接口的这个属性用于在Go中实现多态。

让我们在计算组织净收入的程序的帮助下理解Go中的多态性。为简单起见,我们假设这个想象中的组织有两种项目的收入,即固定账单,时间和材料。该组织的净收入按这些项目的收入总和计算。为了简化本教程,我们假设货币是美元,我们不会处理美分。它将使用int表示。 (我建议阅读https://forum.golangbridge.org/t/what-is-the-proper-golang-equivalent-to-decimal-when-dealing-with-money/413以了解如何代表美分。)

我们首先定义一个 Income接口。

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

上面定义的Income接口包含两个方法calculate(),它计算并返回source和source()的收入,返回source的名称。

接下来让我们为FixedBilling项目类型定义一个结构。

type FixedBilling struct {  
    projectName string
    biddedAmount int
}

FixedBilling项目有两个字段projectName,表示项目的名称,biddedAmount是组织为项目出价的金额。

TimeAndMaterial结构将表示时间和材料类型的项目。

type TimeAndMaterial struct {  
    projectName string
    noOfHours  int
    hourlyRate int
}

TimeAndMaterial结构有三个字段名称projectNamenoOfHourshourlyRate

下一步是定义这些结构类型的方法,这些方法计算并返回实际收入和收入来源。

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项目的情况下,收入就是项目的投标金额。 因此我们从FixedBilling类型的calculate()方法返回它。

对于TimeAndMaterial项目,收入是noOfHourshourlyRate的乘积。 此值从calculate()方法返回,接收器类型为TimeAndMaterial

我们将项目的名称作为source()方法的收入来源返回。

由于FixedBillingTimeAndMaterial结构都为Income接口的calculate()source()方法提供了定义,因此两个结构都实现了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接口的具体类型,将调用不同的calculate()source()方法。 我们在calculateNetIncome函数中实现了多态性。

在未来,如果组织添加了一种新的收入来源,这个功能仍然可以正确计算总收入而无需更改一行代码。

该程序中唯一剩下的部分是主函数。

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函数中,我们创建了三个项目,两个类型为FixedBilling,另一个类型为TimeAndMaterial。 接下来,我们使用这3个项目创建一个类型为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  

在上述计划中添加新的收入流

假设该组织通过广告找到了新的收入来源。 让我们看看添加这个新的收入流并计算总收入是多么简单,而不对calculateNetIncome函数进行任何更改。 由于多态性,这成为可能。

让我们首先在Advertisement类型上定义Advertisement类型和calculate()以及source()方法。

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
}

Advertisement 类型有三个字段:adNameCPC(每次点击费用)和noOfClicks(点击次数)。 广告的总收入是CPCnoOfClicks的产品。

让我们稍微修改一下主函数,以包含这个新的收入流。

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)
}

我们创建了两个广告,即bannerAdpopupAdincomeStreams切片包含我们刚刚创建的两个广告。

这是添加广告后的完整程序。

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  

您会注意到虽然我们添加了新的收入流,但我们没有对calculateNetIncome函数进行任何更改。 它只是因为多态性而起作用。 由于新的Advertisement类型也实现了Income接口,我们可以将它添加到incomeStreams切片中。calculateNetIncome函数也没有任何变化,因为它能够调用Advertisement类型的calculate()source()方法。

猜你喜欢

转载自blog.csdn.net/wyy626562203/article/details/83411447
今日推荐