[关闭]
@adamhand 2019-02-14T12:08:21.000000Z 字数 2637 阅读 742

golang--多态


Go 通过接口来实现多态。

使用接口实现多态

一个类型如果定义了接口的所有方法,那它就隐式地实现了该接口。

通过一个程序我们来理解 Go 语言的多态,它会计算一个组织机构的净收益。假设这个虚构的组织所获得的收入来源于两个项目:fixed billingtime and material。该组织的净收益等于这两个项目的收入总和。假设货币单位是美元。因此货币只需简单地用 int 来表示。

程序如下:

  1. package main
  2. import "fmt"
  3. /*
  4. 收益接口。包含了两个方法:calculate() 计算并返回项目的收入,
  5. 而 source() 返回项目名称。
  6. */
  7. type Income interface {
  8. calculate() int
  9. source() string
  10. }
  11. /*
  12. FixedBilling 项目的结构体类型
  13. 有两个字段:projectName 表示项目名称,而 biddedAmount 表示组织向该项目投标的金额。
  14. */
  15. type FixedBilling struct {
  16. projectName string
  17. biddedAmount int
  18. }
  19. /*
  20. TimeAndMaterial项目结构体类型
  21. 拥有三个字段名:projectName、noOfHours 和 hourlyRate。
  22. */
  23. type TimeAndMaterial struct {
  24. projectName string
  25. noOfHours int
  26. hourlyRate int
  27. }
  28. /*
  29. 实现接口
  30. */
  31. func (fb FixedBilling)calculate() int {
  32. return fb.biddedAmount
  33. }
  34. func (fb FixedBilling)source() string {
  35. return fb.projectName
  36. }
  37. func (tm TimeAndMaterial)calculate() int {
  38. return tm.hourlyRate * tm.noOfHours
  39. }
  40. func (tm TimeAndMaterial)source() string {
  41. return tm.projectName
  42. }
  43. /*
  44. 计算收益
  45. 根据 Income 接口的具体类型,程序会调用不同的 calculate() 和 source() 方法
  46. 于是,在 calculateNetIncome 函数中就实现了多态。
  47. */
  48. func calculateIncome(ic []Income) {
  49. var totalIncome int = 0
  50. for _, income := range ic{
  51. fmt.Printf("income from %s is $%d\n", income.source(), income.calculate())
  52. totalIncome += income.calculate()
  53. }
  54. fmt.Printf("total income is $%d\n", totalIncome)
  55. }
  56. func main() {
  57. project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}
  58. project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}
  59. project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
  60. incomeStreams := []Income{project1, project2, project3}
  61. calculateIncome(incomeStreams)
  62. }

上述程序的执行结果为:

  1. income from Project 1 is $5000
  2. income from Project 2 is $10000
  3. income from Project 3 is $4000
  4. total income is $19000

新增收益流

假设前面的组织通过广告业务,建立了一个新的收益流(Income Stream)。添加它非常简单,并且计算总收益也很容易,无需对 calculateNetIncome 函数进行任何修改。这就是多态的好处。

首先定义 Advertisement 类型,并在 Advertisement 类型中定义 alculate()source() 方法。

Advertisement 类型有三个字段,分别是 adNameCPC(每次点击成本)和 noOfClicks(点击次数)。广告的总收益等于 CPCnoOfClicks 的乘积。

  1. type Advertisement struct {
  2. adName string
  3. CPC int
  4. noOfClicks int
  5. }
  6. func (ad Advertisement)calculate() int {
  7. return ad.noOfClicks * ad.CPC
  8. }
  9. func (ad Advertisement)source() string {
  10. return ad.adName
  11. }

稍微修改一下 main 函数,创建了两个广告项目,即 bannerAdpopupAdincomeStream,把新的收益流添加进来。

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

然后程序的输出结果Wie:

  1. income from Project 1 is $5000
  2. income from Project 2 is $10000
  3. income from Project 3 is $4000
  4. income from Banner Ad is $1000
  5. income from Popup Ad is $3750
  6. total income is $23750
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注