Lesson Introduction

Hello! Today, we'll delve into design patterns in Go with practical exercises that apply these fundamental principles to solve problems. Mastering these concepts will enhance your coding skills and understanding.

Our focus today is to strengthen your understanding of how and when to apply specific Go design concepts using structs, interfaces, and composition. These include Encapsulation, Abstraction, Polymorphism, and Composition through Go’s distinct approach.

We'll explore four real-life scenarios, examining which pattern is applicable and why, using Go’s unique features. Let's dive in!

Real-life Example 1: Database Management System (Encapsulation)

In Go, Encapsulation is achieved using structs and package-level visibility. We use unexported fields and methods to control data access and promote data integrity.

package main

import (
    "fmt"
)

type Employees struct {
    employees map[int]string // unexported field
}

func NewEmployees() *Employees {
    return &Employees{employees: make(map[int]string)}
}

func (e *Employees) AddEmployee(id int, name string) { // method to operate on unexported data
    e.employees[id] = name
}

func (e *Employees) UpdateEmployee(id int, newName string) { // method to operate on unexported data
    if _, exists := e.employees[id]; exists {
        e.employees[id] = newName
    }
}

func (e *Employees) GetEmployee(id int) string { // method to get unexported data
    if name, exists := e.employees[id]; exists {
        return name
    }
    return ""
}

func main() {
    employees := NewEmployees()
    employees.AddEmployee(1, "John")
    employees.AddEmployee(2, "Mark")

    employees.UpdateEmployee(2, "Jake")

    fmt.Println(employees.GetEmployee(1)) // Outputs: John
    fmt.Println(employees.GetEmployee(2)) // Outputs: Jake
}

Here, Encapsulation restricts direct access to the employee data, using methods to interact with the stored information securely.

Real-life Example 2: Graphic User Interface (GUI) Development (Polymorphism)

In Go, Polymorphism is achieved through interfaces, allowing different structs to define specific behaviors for the same method.

package main

import (
    "fmt"
)

type Clickable interface {
    Click()
}

type Button struct{}

func (b Button) Click() {
    fmt.Println("Button Clicked!")
}

type CheckBox struct{}

func (c CheckBox) Click() {
    fmt.Println("CheckBox Clicked!")
}

func main() {
    var b Clickable = Button{}
    var c Clickable = CheckBox{}

    // Click Controls
    b.Click() // Outputs: Button Clicked!
    c.Click() // Outputs: CheckBox Clicked!
}

Interfaces in Go allow Polymorphism, enabling different structs to share behavior provided by the Clickable interface.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal