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]
}
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)
}
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)
}
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)
}
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)