在 Go
中,多态的实现用到了接口。
接下来,我们来讨论下:通过接口,Go
是如何实现多态的。
在 Go
语言中,接口能被隐式实现。如果 类型 定义了接口的所有方法,那该类型就实现了接口。
接口类型的变量,能存储 任意实现了该接口的对象。利用这个属性,我们就能在 Go
中实现多态。
接下来,我们将通过程序理解多态,这个程序的功能是:计算公司的总收入。这家公司的收入来源于 2
类工程,分别为 fixed billing
类、 time and material
类。公司的总收入 等于 这 2
类工程收入的总和。
我们先定义一个接口:
type Income interface {
calculate() int
source() string
}
从上面的程序可以看出,Income
接口 包括 2
个方法。calculate
方法 用于计算并返回收入,source
方法 用于返回收入来源的名称。
接下来,我们来定义 FixedBilling
、TimeAndMaterial
结构。
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
字段 表示每小时能获得的收入。
接下来,我们让 FixedBilling
、TimeAndMaterial
结构 实现 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
类 的工程来说,收入等于 noOfHours
和 hourlyRate
的乘积。因此,该类型的 calculate
方法 返回 noOfHours * hourlyRate
。
对于上面 2
类工程来说,source
方法 都返回它们的工程名。
由于 FixedBilling
、TimeAndMaterial
结构 具有了 Income
接口 的所有方法,所以FixedBilling
、TimeAndMaterial
结构 实现了 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
函数 中实现了多态。
在之后,如果公司又有新的收入来源。只要该收入来源实现了 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
个类型为 FixedBilling
,1
个类型为 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
}
Advertisement
有 3
个字段,分别为 adName
、CPC
、noOfClicks
。它的收入计算公式是: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
的变量,它们分别名为 bannerAd
、popupAd
。之后,它们被加入 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
这就是多态了~
祝你天天向上~
优质内容来之不易,您可以通过该 链接 为我捐赠。
感谢原作者的优质内容。
欢迎指出文中的任何错误。