Hello, welcome back! Today, we will delve into the fundamentals of Basic Design Patterns — specifically, Composition! A critical pattern in software design, composition helps us create complex types by combining simpler components using Go's structs and interfaces. Our journey today will explore the concept of composition, its value in software development, and how to implement it practically in Go.
To kick-start our exploration, let's understand Composition
. In software design, composition refers to the way we combine simpler types into a more complex system using structs and interfaces in Go. For example, when constructing a car, we bring together components like the Engine
, Wheels
, and Seats
. In composition, if the parent object (the car) ceases to exist, the encapsulated components generally cease to exist as well, reflecting real-world dependencies.
Now, let's translate the theory into Go. We’ll show how a Car
can be composed by encapsulating the Engine
, Wheels
, and Seats
structs within it. The Car
will own these components, and their lifecycles are managed within the Car
.
Go1package main 2 3import ( 4 "fmt" 5) 6 7type Engine struct{} 8 9func (e Engine) Start() { 10 fmt.Println("Engine starts") 11} 12 13func (e Engine) Stop() { 14 fmt.Println("Engine stops") 15} 16 17type Wheels struct{} 18 19func (w Wheels) Rotate() { 20 fmt.Println("Wheels rotate") 21} 22 23type Seats struct{} 24 25func (s Seats) Adjust(position string) { 26 fmt.Println("Seats adjusted to position", position) 27} 28 29type Car struct { 30 engine Engine 31 wheels Wheels 32 seats Seats 33} 34 35func (c *Car) Start() { 36 c.engine.Start() // Call to start engine 37 c.seats.Adjust("upright") // Adjust seat position 38 c.wheels.Rotate() // Get wheels rolling 39} 40 41func main() { 42 myCar := &Car{ 43 engine: Engine{}, 44 wheels: Wheels{}, 45 seats: Seats{}, 46 } 47 myCar.Start() // Begin car functions 48} 49 50// Prints: 51// Engine starts 52// Seats adjusted to position upright 53// Wheels rotate
In the above code, the Car
struct encapsulates the Engine
, Wheels
, and Seats
structs, creating a composition pattern. These components are composed rather than subclassed, enabling reuse in different contexts.
In software design, Composition
and Inheritance
are two ways to express relationships among types. In Go, composition is achieved through struct embedding and method utilization, equating to a "has-a" relationship. Unlike traditional inheritance, which Go does not support, composition allows for more flexible code reuse and component encapsulation.
Excellent job! You’ve now decoded composition and have seen its implementation in Go! As you practice further, you'll encounter exercises that solidify your understanding of composition in Go. Stay curious, and keep practicing to reinforce your concepts!