golang教程之多型性-Go面向物件
文章目錄
多型性-Go面向物件
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結構有三個欄位名稱projectName
,noOfHours
和hourlyRate
。
下一步是定義這些結構型別的方法,這些方法計算並返回實際收入和收入來源。
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
專案,收入是noOfHours
和hourlyRate
的乘積。 此值從calculate()
方法返回,接收器型別為TimeAndMaterial
。
我們將專案的名稱作為source()
方法的收入來源返回。
由於FixedBilling
和TimeAndMaterial
結構都為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
型別有三個欄位:adName
,CPC
(每次點選費用)和noOfClicks
(點選次數)。 廣告的總收入是CPC
和noOfClicks
的產品。
讓我們稍微修改一下主函式,以包含這個新的收入流。
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)
}
我們建立了兩個廣告,即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
您會注意到雖然我們添加了新的收入流,但我們沒有對calculateNetIncome
函式進行任何更改。 它只是因為多型性而起作用。 由於新的Advertisement
型別也實現了Income
介面,我們可以將它新增到incomeStreams
切片中。calculateNetIncome
函式也沒有任何變化,因為它能夠呼叫Advertisement
型別的calculate()
和source()
方法。