Introduction and Lesson Goal

Today's mission involves leveraging various programming principles in Go to tackle complex tasks effectively. When principles like Encapsulation, Abstraction, Polymorphism, and Composition are blended, the resulting code becomes streamlined and easier to manage.

Our goal is to explore two real-world examples, demonstrating how these principles can seamlessly orchestrate solutions using structs, interfaces, and composition in Go.

Real-life Example 1: Building an Online Library System

We'll design an online library system to reinforce our understanding of Encapsulation and Polymorphism in Go. Encapsulation will help us guard the attributes of books, members, and transactions, ensuring controlled access. Polymorphism will illustrate its utility by enabling a single interface to represent different underlying forms, such as digital and print versions of books.

package main

import (
    "fmt"
)

// Struct defining a library member
type Member struct {
    name string
}

// Method for a member to check out a book
func (m *Member) CheckOutBook(book Book) {
    fmt.Printf("%s checked out %s book %s.\n", m.name, book.GetBookType(), book.GetTitle())
}

// Interface for different types of books
type Book interface {
    GetBookType() string
    GetTitle() string
}

// Struct representing a digital book
type DigitalBook struct {
    title string
}

// Implementing Book interface for DigitalBook
func (d DigitalBook) GetBookType() string {
    return "Digital"
}

func (d DigitalBook) GetTitle() string {
    return d.title
}

// Struct representing a physical book
type PhysicalBook struct {
    title string
}

// Implementing Book interface for PhysicalBook
func (p PhysicalBook) GetBookType() string {
    return "Physical"
}

func (p PhysicalBook) GetTitle() string {
    return p.title
}

// Struct representing a library to manage members and books
type Library struct {
    members []Member
    books   []Book
}

// Method to add a member
func (l *Library) AddMember(member Member) {
    l.members = append(l.members, member)
}

// Method to add a book
func (l *Library) AddBook(book Book) {
    l.books = append(l.books, book)
}

func main() {
    myLibrary := Library{}

    alice := Member{"Alice"}
    bob := Member{"Bob"}

    myLibrary.AddMember(alice)
    myLibrary.AddMember(bob)

    digitalBook := DigitalBook{"The Go Handbook"}
    physicalBook := PhysicalBook{"Learning Go Design Patterns"}

    myLibrary.AddBook(digitalBook)
    myLibrary.AddBook(physicalBook)

    alice.CheckOutBook(digitalBook)  // Prints: Alice checked out Digital book The Go Handbook.
    bob.CheckOutBook(physicalBook)   // Prints: Bob checked out Physical book Learning Go Design Patterns.
}

In this code snippet, Encapsulation is demonstrated by using Go structs to contain member and book details. Polymorphism is illustrated by how both DigitalBook and PhysicalBook structs implement the Book interface, allowing them to be used interchangeably when identifying the type of a book. This setup shows how polymorphism in Go allows working with different types through common interface definitions.

  • Encapsulation secures member and book information within their respective structs.
  • Polymorphism permits uniform handling of different book types, enhancing system adaptability.
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