DEV Community

Cover image for Façade Design Pattern in Go
Tomas Sirio
Tomas Sirio

Posted on

Façade Design Pattern in Go

Hey there!

This is a late post in the week, but let's get into it.

Let's assume you are trying to build a new API for a CLI. In this case, we are going to build a limited size console.

On our console, we are going to have a buffer of runes which we are going to be able to add, remove, or consult at any time.

So for example, let's see how it'd be built:

type Buffer struct {
    width, height int
    buffer        []rune
}

func NewBuffer(width int, height int) *Buffer {
    return &Buffer{width, height, make([]rune, width*height)}
}

func (b *Buffer) At(index int) rune {
    return b.buffer[index]
}
Enter fullscreen mode Exit fullscreen mode

In order to keep the example short, we are only going to add define the At method which will consult the character (or rune) at the 'index' index.

So, we now have a Buffer for our console and a constructor. And this would work for everyone, however, we want to give the user a not so complex interface in order to use our console. They'll be able to handle the Buffers if they want to do so, but we are going to handle them with an interface that configures the structures for them.

So then, let's give them a viewport to handle that buffer

type Viewport struct {
    buffer *Buffer
    offset int
}

func NewViewport(buffer *Buffer) *Viewport {
    return &Viewport{buffer: buffer}
}

func (v *Viewport) GetCharaterAt(index int) rune {
    return v.buffer.At(v.offset + index)
}
Enter fullscreen mode Exit fullscreen mode

Right now, the user can interact with a portion of the buffer without the need of getting it in it's totality since some buffers can get really big to handle.

Again, we are letting the user interact with the viewport if they please by using it's constructor and methods.

Finally, we can add the so-called Façade for our program:

type Console struct {
    buffers   []*Buffer
    viewports []*Viewport
    offset    int
}

func NewConsole() *Console {
    b := NewBuffer(200, 150)
    v := NewViewport(b)
    return &Console{[]*Buffer{b}, []*Viewport{v}, 0}
}

func (c *Console) GetCharaterAt(index int) rune {
    return c.viewports[0].GetCharaterAt(index)
}
Enter fullscreen mode Exit fullscreen mode

On our console, we can have as many buffers and viewports as we want. Most systems will be initialized with just one of each, but that could easily be handled with another constructor in which we can specify how many of which we want or we can just add them to our buffers and viewports variables inside our Console instance.

func main() {
    c := NewConsole()

    u := c.GetCharaterAt(1)

    fmt.Println(u)

}
Enter fullscreen mode Exit fullscreen mode

The user only has to initialize a console with it's constructor without having to think about the complexity behind the program and thus the façade works as intended.

Top comments (0)