Go series of tutorials - 28. polymorphism

Welcome to  Golang tutorial series on the 28.

Go through the interface to achieve polymorphism. We have discussed, in the Go language, we are implicitly implement interfaces. If a type defines all the interfaces declared method , then it implements this interface. Now let's see, using the interface, how Go is to achieve polymorphism.

Interface using polymorphism

If a type defines all methods of the interface, then it implicitly implements this interface.

All realized the type of interface, its value can be stored in an interface type of the variable. In Go, we use this feature interfaces to achieve polymorphism .

Through a program we have to understand the language of the polymorphic Go, it will calculate the net income of an organization. For simplicity, we assume that the two projects revenues this fictional organization obtained from: fixed billing and  time and material. The organization's net income is equal to the sum of these two projects. Also for the sake of simplicity, we assume that the currency is the dollar, without having to deal cents. So money simply use  int to represent. (I recommend reading  https://forum.golangbridge.org/t/what-is-the-proper-golang-equivalent-to-decimal-when-dealing-with-money/413  article to learn how to express cents thanks Andreas Matuschek pointed this out in the comments section.)

We first define an interface  Income.

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

Above defines the interface  Interfacethat contains two methods: calculate() the calculation of income and return of items, and  source() returns the project name.

Here we define a representation  FixedBilling structure types of items.

type FixedBilling struct { projectName string biddedAmount int } 

Project  FixedBillin has two fields: projectName indicate the project name, and  biddedAmount indicate the amount of tissue to the project bid.

TimeAndMaterial Structure used to represent item Time and Material.

type TimeAndMaterial struct { projectName string noOfHours int hourlyRate int } 

The structure  TimeAndMaterial has three fields projectNamename: , noOfHours and  hourlyRate.

Next we define methods for these types of structures, calculation and returns the actual income and project name.

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 } 

In the project  FixedBilling there, the bid amount of revenue that project. So we return  FixedBilling type of  calculate() the method.

In projects  TimeAndMaterial which, revenue equals  noOfHours and  hourlyRate the product, as the  TimeAndMaterial type of  calculate() the return value.

We also  source() returned the item name represents a source of income method.

Because  FixedBilling and  TimeAndMaterial two structures defines  Income two interface methods: calculate() and  source(), so that the two structures are implemented  Income interfaces.

We declare a  calculateNetIncome function to calculate and print the total revenue.

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

The above function of receiving an  Income interface type of the slice as a parameter. This function will traverse this interface sections, and in accordance with a call  calculate() method, calculate the total income. By calling the function will also  source() display the source of income. According to  Income the specific type of interface, the program will call different  calculate() and  source() methods. So, we  calculateNetIncome function on the realization of polymorphism.

If you added a new source of income in the future of the organization, calculateNetIncome without having to modify a line of code, you can calculate the total income correctly.:smile:

Finally, the rest of this program  main function of.

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

In the above  main function, we created three projects, there are two  FixedBilling types, one is the  TimeAndMaterial type. Then we created a  Income type of slice, stored for three projects. Since these three projects are implemented  Interface interface, so you can put the project into three  Income sections. Finally, we slice this as an argument, call the  calculateNetIncome function, it shows the different project income and sources of income.

The following complete code for your reference.

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

 

The program will output:

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

New revenue stream

And assume that the organization through advertising, set up a new revenue stream (Income Stream). We can see it is very simple to add, and calculate the total income is also very easy, we do not need to  calculateNetIncome function to make any changes. This is a multi-state benefits.

We first define  Advertisement the type and  Advertisement define the types  calculate() and  source() methods.

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 There are three types of fields, namely  adName, CPC(cost per click) and  noOfClicks(clicks). Total advertising revenue is equal  CPC and  noOfClicks the product.

Now we slightly modify  main function, the new revenue streams added.

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

We created two advertising projects, namely  bannerAd and  popupAd. incomeStream Slice contains two advertising projects created.

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

 

The above program will output:

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 

You will find that even though we have added revenue streams, but did not modify the  calculateNetIncome function. That's the beauty of polymorphism brings. Because the new  Advertisement same implements  Income the interface, so we are able to  incomeStreams add slices  Advertisement. calculateNetIncome Without modification, because it can call  Advertisement types  calculate() and  source() methods.

This tutorial is over. wish you happiness.

Guess you like

Origin www.cnblogs.com/fengchuiyizh/p/11356106.html