Unlocking the Power of Extension Objects: The Easy, Elegant, and Flexible Approach in Go

Photo by Ksenia Chernaya: https://www.pexels.com/photo/interior-of-modern-house-during-renovation-process-5691530/

Introduction

The extension object pattern is a clever way to add new features to an existing object without changing its original code. It’s like wrapping a present within a present – the outer one directs requests to the inner one. In the world of programming, Go provides built-in support for this feature, making it easy to extend an object’s capabilities. In this article, we’ll explore how to use extension objects in Go, and you’ll be pleasantly surprised at how elegant and flexible this technique can be.

Implementation in Go

To demonstrate this concept, let’s imagine we’re creating a simple windowing system. We start with a BasicWindow that can open and close windows. However, sometimes we need to do more, like rotating windows. So, we introduce an ExtendedWindow.

Here are the basics:

package main

import "fmt"

type BasicWindowInterface interface {
	Open()
	Close()
}

type BasicWindow struct {
	title string
}

func (bw *BasicWindow) Open() {
	fmt.Printf("Opening window with title %s\n", bw.title)
}

func (bw *BasicWindow) Close() {
	fmt.Printf("Closing window with title %s\n", bw.title)
}

func createWindow(title string) BasicWindow {
	return BasicWindow{
		title: title,
	}
}

Some points to note:

  1. The BasicWindow only requires a title.
  2. Open() and Close() methods print out messages.
  3. createWindow() function creates a BasicWindow.

Next let’s introduce the ExtendedWindow

type ExtendedWindow struct {
	BasicWindow
}

func (ew *ExtendedWindow) Rotate(degrees int32) {
	fmt.Printf("Rotating window with title %s by %d degrees\n", ew.BasicWindow.title, degrees)
}

func createExtendedWindow(window BasicWindow) ExtendedWindow {
	return ExtendedWindow{
		window,
	}
}

Here’s what’s happening:

  1. ExtendedWindow embeds the BasicWindow.
  2. We add a Rotate() method.
  3. createExtendedWindow() function creates an ExtendedWindow with a BasicWindow.

What’s cool is that we never changed the code of the BasicWindow. All the extra functionality is implemented in the ExtendedWindow, showcasing the power of Go’s embedding feature

Time to test

Now let’s put it to the test:

func main() {
	window := createWindow("First window")
	extendedWindow := createExtendedWindow(window)
	extendedWindow.Open()
	extendedWindow.Rotate(45)
	extendedWindow.Close()
}

In summary:

  1. We create a BasicWindow and use it to create an ExtendedWindow.
  2. We call Open(), Rotate(), and Close() on the ExtendedWindow, and thanks to embedding, these calls are automatically delegated to the BasicWindow.

Conclusion

When I first encountered embedding in Go, I underestimated its importance. But as you’ve seen, it’s a powerful and flexible feature. Using embedding to implement the extension object pattern keeps your code clear, elegant, and maintainable. However, it’s essential to note that embedding and subclassing aren’t the same, and in certain cases, when you need to embed multiple objects implementing the same interface, it might not be as elegant. But for many scenarios, embedding in Go is a fantastic tool to have in your programming arsenal.

Leave a Reply

Your email address will not be published. Required fields are marked *