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 Interface
that 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 projectName
name: , 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.
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: