Composition in Golang


Composition is a powerful concept in object-oriented programming that allows creating complex types by combining smaller, simpler types. It enables building new types that have the functionality of several existing types, without the need to inherit from them. In Go, composition is achieved using struct embedding, a language feature that allows embedding one struct type inside another.

In this article, we will explore how composition works in Go and how it can be used to create more flexible and modular programs.

What is Composition?

Composition is a mechanism that enables combining simpler types to create more complex ones. It is a fundamental concept in object-oriented programming that allows reusing code and building more flexible and modular programs.

Composition is often used to solve problems that arise from using inheritance, such as the fragile base class problem or the diamond problem. Unlike inheritance, composition is based on the idea of "has-a" relationships, rather than "is-a" relationships. That means that a type composed of several other types has the functionality of those types, but it is not a subtype of them.

In Go, composition is achieved using struct embedding, a language feature that allows embedding one struct type inside another. This enables the created type to inherit the fields and methods of the embedded type, and to use them as if they were its own.

Composition with Struct Embedding

Struct embedding is the primary mechanism for achieving composition in Go. It allows embedding one struct type inside another, creating a new type that has the fields and methods of both types. The embedded type is referred to as the embedded struct, and the embedding type is referred to as the embedding struct.

The syntax for embedding a struct type is as follows −

type EmbeddedType struct {
   // Fields and methods of the embedded type
}

type EmbeddingType struct {
   // Fields of the embedding type
   EmbeddedType // Embedding the embedded type
   // Additional fields and methods of the embedding type
}

In this example, the EmbeddingType struct embeds the EmbeddedType struct using the name of the embedded type as a field name. This enables the EmbeddingType struct to inherit the fields and methods of the EmbeddedType struct, and to use them as if they were its own.

Example

package main

import (
   "fmt"
)

// Embedded struct
type Person struct {
   Name string
   Age  int
}

// Embedding struct
type Employee struct {
   Person      // Embedding the Person struct
   CompanyName string
}

func main() {
   // Creating an Employee object
   emp := Employee{
      Person: Person{
         Name: "John Doe",
         Age:  35,
      },
      CompanyName: "ACME Corp",
   }

   // Accessing the embedded Person object
   fmt.Println("Employee Name:", emp.Name)
   fmt.Println("Employee Age:", emp.Age)

   // Accessing the fields of the embedding object
   fmt.Println("Employee Company:", emp.CompanyName)
}

Output

Employee Name: John Doe
Employee Age: 35
Employee Company: ACME Corp

In this example, we create two struct types, Person and Employee. The Person struct has two fields, Name and Age, and the Employee struct embeds the Person struct using the Person field name. This enables the Employee struct to inherit the fields and methods of the Person struct.

We then create an Employee object, emp, and set its Name, Age, and CompanyName fields. We can access the fields of the embedded Person object using dot notation, as if they were fields of the Employee object. We can also access the fields of the embedding object using dot notation.

Composition vs. Inheritance

Composition and inheritance are two ways to achieve code reuse and build complex systems. Inheritance is a mechanism that allows a class to inherit properties and behavior from a parent class. Composition is a way of building complex objects by combining smaller, simpler objects.

In Go, composition is favored over inheritance. This is because Go does not have classes like traditional object-oriented programming languages. Instead, Go uses structs to define objects and interfaces to define behavior. Composition is achieved by embedding one struct into another.

Let's compare the two approaches with an example.

Inheritance Example

Suppose we have a parent class called Animal and two child classes called Dog and Cat. The Animal class has a method called MakeSound, and the Dog and Cat classes inherit this method from the Animal class.

type Animal struct {
}

func (a *Animal) MakeSound() {
   fmt.Println("Generic animal sound")
}

type Dog struct {
   *Animal
}

type Cat struct {
   *Animal
}

In the above code, we have defined an Animal class with a method MakeSound. The Dog and Cat classes are defined as child classes of the Animal class and inherit the MakeSound method.

Composition Example

Let's rewrite the above example using composition.

type Animal struct {
   sound string
}

func (a *Animal) MakeSound() {
   fmt.Println(a.sound)
}

type Dog struct {
   animal *Animal
}

type Cat struct {
   animal *Animal
}

In the above code, we have defined an Animal struct with a method MakeSound. The Dog and Cat structs contain a pointer to an Animal struct. The MakeSound method of the Animal struct is called on the Animal struct contained in the Dog or Cat struct.

Composition is a more flexible approach than inheritance because it allows you to combine different types of objects to create a more complex object. It also avoids the pitfalls of inheritance, such as tight coupling and the fragile base class problem.

Conclusion

In conclusion, composition is a powerful tool in Go that allows you to build complex objects by combining smaller, simpler objects. It is a flexible and scalable approach that can help you build robust and maintainable systems. Go favors composition over inheritance, as it offers more flexibility and avoids the pitfalls of inheritance. When designing your Go applications, consider using composition to create more maintainable and scalable code.

Updated on: 07-Apr-2023

4K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements