OOPs concepts in Golang in detail
Object Oriented Programming in Golang
Class is the most important concept of object-oriented programming. Class in practical terms a definition to store and create data and functions to work on them in the memory of a computer while the app is running. It’s a blueprint to define a set of data or objects and functions associated with them.
An object is data which has been modelled as per a particular class.
Encapsulation is the most important concept in object-oriented programming. Encapsulation means the abstraction of data contained in a class. It is a way of organizing the code where access to data is not provided to the application developers. They are provided with class methods and those methods make changes to the data.
This approach is followed to make the application clean, bug-free and scalable in terms of functionality.
Golang doesn’t have a class like any other object-oriented programming language. The main purpose of the class is to combine the data and the functionality together. Go does it by declaring the receiver function on a particular type.
We define the data as type and then the receiver function on that type to manipulate the data below is the example.
package oops
type Int int
func (a *Int) Add_One() {
*a = *a + 1
}
import (
"fmt"
oops "github.com/uditsaurabh/go-book/OOPS"
)
func main() {
var a oops.Int = 10
a.Add_One()
fmt.Println(a)
}
C:\Users\lenovo\OneDrive\Desktop\Projects\go-projects\go-book>go run .
11
We can define the receiver function in two ways namely the pointer receiver function and the normal receiver function. The pointer receiver function has a reference of the main variable on which it’s been called. So whatever changes we do to it will be reflected in the main variable but in the case of using the normal receiver function we have a copy of the original receiver function and we have to return and save it in order to reflect the changes. We can access the receiver function on the particular type using dot notation.
package oops
type Int int
func (a *Int) Add_One() {
*a = *a + 1
}
func (a Int) Double() Int {
return (a * 2)
}
import (
"fmt"
oops "github.com/uditsaurabh/go-book/OOPS"
)
func main() {
var a oops.Int = 10
a.Add_One()
fmt.Println(a)
// - - - - - - - - - - - - -
fmt.Println(a.Double())
}
O/P
C:\Users\lenovo\OneDrive\Desktop\Projects\go-projects\go-book>go run .
11
22
When we need to show multiple data in that case we can group the data using the struct and display it as shown below. Also, the most important thing you will find is that in the pointer receiver function in this case Print_Details we don’t have to dereference the pointer, in our case player variable in Print_Details. It’s a go feature and is provided for convenience.
type Player struct {
Name string
Age int
Sports string
}
func (player *Player) Print_Details() {
fmt.Println("Player name is", player.Name, "Player age is", player.Age, "player Sports is", player.Sports)
}
package main
import (
"fmt"
oops "github.com/uditsaurabh/go-book/OOPS"
)
func main() {
p1 := oops.Player{
Name: "Udit",
Age: 29,
Sports: "football",
}
fmt.Println(p1)
}
Output
C:\Users\lenovo\OneDrive\Desktop\Projects\go-projects\go-book>go run .
{Udit 29 football}
So struct with their receiver function replicates almost a class and also performs encapsulation and abstraction.
Polymorphism
It’s another very important concept of object-oriented programming. Polymorphism means the ability of an object to have different forms based on situations and scenarios. This means in the context of Go that the same function can do different work based on the user input. Polymorphism can be achieved in other programming languages using method overriding (inheritance). But Go does not support inheritance. In another language, we define a method in the parent class and override it in the child class to add different functionality. Go achieve it using interfaces.
Interface
The interface is a set of method signatures. So the method has the name, signature and return values. It is used to express conceptual similarity between types. Here in the example below, we will see how to achieve polymorphism in go. Here two structs Squares and Rectangle are implementing the interface shape and we are creating two different variables namely square_area and rectangle_area of type Shape Interface but passing the Square and Rectangle object to them. Since both these structs have implemented the interface Shape so a shape variable can contain the object of type Square and Rectangle and then when we call area using square_area the area method of the square is called and when we call area to function on rectangle _area variable area method for Rectangle struct gets called. So the idea is for the same type of variable Shape we are able to invoke the same kind of functionality and this is polymorphism.
So the key point is that any interface which is implemented by a type, its object can be contained in that interface variable.
package oops
type Shape interface {
Area() int
}
type Square struct {
Length int
}
type Rectangle struct {
Length int
Breadth int
}
func (s Square) Area() int {
return s.Length * s.Length
}
func (s Rectangle) Area() int {
return s.Length * s.Breadth
}
package main
import (
"fmt"
oops "github.com/uditsaurabh/go-book/OOPS"
)
func main() {
var s oops.Shape = oops.Square{Length: 10}
square_area := s.Area()
fmt.Println(square_area)
var r oops.Shape = oops.Rectangle{Length: 10, Breadth: 20}
rectangle_area := r.Area()
fmt.Println(rectangle_area)
}
C:\Users\lenovo\OneDrive\Desktop\Projects\go-projects\go-book>go run .
100
200