Design Patterns in Golang: Prototype

Preface

The Prototype Pattern creates duplicate objects while keeping performance
in mind. It’s a part of the creational patterns and provides one of the best
ways to create an object.

In the mainstream languages (like C# and JAVA), it requires implementing a
prototype interface which tells to create a clone of the current object. It is
used when creation of object directly is costly.

For instance, an object is to be created after a costly database operation. We
can cache the object, returns its clone on next request and update the database
as and when needed thus reducing database calls.

Purpose

Specify the kind of objects to create using a prototypical instance, and
create new objects by copying this prototype.

Design Pattern Diagram

Prototype declares an interface for cloning itself

ConcretePrototype implements an operation for cloning itself

Client creates a new object by asking a prototype to clone itself

Implementation

In Golang, the pattern is applicable only in situation that we want to
customize how the object is cloned. We will explore two examples regarding
both situations.

Lets build a system that generates a different configuration files depending on
our needs. In first place, we have a struct Config that looks like:

We want to be able to mutate the object without affecting its initial instance.
The goal is to be able to generate different configuration files without loosing
the flexibility of customizing them without mutation of the initial default
configuration.

As you can see the functions WithWorkDir, WithUser are declared for the
struct Config (not for *Config). At the time, when they are called the
object is copied by the Golang runtime. This allows us to modify it
without affecting the original object.

Now lets explore the classic implementation of The Prototype Design Pattern.
We will assume that we are developing again document object model for a custom
document format. The core object is an Element structure which has parent and
children.

Verdict

One of the disadvantages of this pattern is that the process of copying an object
can be complicated. In addition, structs that have circular references to other
classes are difficult to clone. Its overuse could affect performance, as the
prototype object itself would need to be instantiated if you use a registry of
prototypes.

In the context of Golang, I don’t see any particular reason to adopt it.
Golang already provides builtin mechanism for cloning objects.