Trusted answers to developer questions

What is the Façade Design Pattern in Go?

Get Started With Data Science

Learn the fundamentals of Data Science with this free course. Future-proof your career by adding Data Science skills to your toolkit — or prepare to land a job in AI, Machine Learning, or Data Analysis.

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 that we can add, remove, or consult at any time.

So, let’s see how this will 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]
}

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.

We now have a Buffer for our console and a constructor. This would work for everyone; however, we should give the user a less complex interface to work with as they use our console. The user will be able to handle the Buffers if they want to, but we are going to handle them with an interface that configures the structures for them.

So, 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)
}

Right now, the user can interact with a portion of the buffer without needing to get it to its totality, as some buffers can get too big to handle.

Again, we are letting the user interact with the viewport, if they want, by using its constructor and methods.

Finally, we can add the so-called “Façade” to 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)
}

On our console, we can have as many buffers and viewports as we want. Most systems are initialized with just a buffer or a viewport; however, this can easily be handled by adding another constructor in which we can specify how many and of what we want, and then add them to the buffer and viewport variables inside our Console instance.

func main() {
    c := NewConsole()

    u := c.GetCharaterAt(1)

    fmt.Println(u)

}

The user only has to initialize a console with its constructor without having to think about the complexity behind the program; thus, the façade works as intended.

Code

package main
import "fmt"
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]
}
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)
}
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)
}
func main() {
c := NewConsole()
u := c.GetCharaterAt(1)
fmt.Println(u)
}

RELATED TAGS

go

CONTRIBUTOR

Tomas Sirio
Attributions:
  1. undefined by undefined
Copyright ©2024 Educative, Inc. All rights reserved
Did you find this helpful?