DEV Community

murugan
murugan

Posted on

Golang Design Patterns

Design Patterns in go

Creational design pattern

- Abstract design Pattern

  • Singleton Pattern
  • Builder
  • Factory
  • Object Pool
  • Prototype
Enter fullscreen mode Exit fullscreen mode

Abstract Factory Design Pattern in Go

Definition:

Abstract Factory Design Pattern is a creational design pattern that lets you create a family of related objects. It is an abstraction over the factory pattern.

Example use cases:

Imagine you need to buy a sports kit which has a shoe and short. Preferably most of the time you would want to buy a full sports kit of a similar factory i.e either nike or adidas. This is where the abstract factory comes into the picture as concrete products that you want is shoe and a short and these products will be created by the abstract factory of nike and adidas.
Both these two factories – nike and adidas implement iSportsFactory interface.
We have two product interfaces.

iShoe – this interface is implemented by nikeShoe and adidasShoe concrete product.
iShort – this interface is implemented by nikeShort and adidasShort concrete product.

Builder Pattern in GoLang

Builder Pattern is a creational design pattern used for constructing complex objects.

When To Use:

  • Use Builder pattern when the object constructed is big and requires multiple steps. It helps in less size of the constructor. The construction of the house becomes simple and it does not require a large constructor

  • When a different version of the same product needs to be created. For example, in the below code we see a different version of house ie. igloo and the normal house being constructed by iglooBuilder and normalBuilder

  • When half constructed final object should not exist. Again referring to below code the house created will either be created fully or not created at all. The Concrete Builder struct holds the temporary state of house object being created

Factory Design Pattern in Go

Factory design pattern is a creational design pattern and it is also one of the most commonly used pattern. This pattern provides a way to hide the creation logic of the instances being created.
The client only interacts with a factory struct and tells the kind of instances that needs to be created. The factory class interacts with the corresponding concrete structs and returns the correct instance back.

When To Use:

  • We have iGun interface which defines all methods a gun should have
  • There is gun struct that implements the iGun interface.
  • Two concrete guns ak47 and maverick. Both embed gun struct and hence also indirectly implement all methods of iGun and hence are of iGun type
  • We have a gunFactory struct which creates the gun of type ak47 or maverick.
  • The main.go acts as a client and instead of directly interacting with ak47 or maverick, it relies on gunFactory to create instances of ak47 and maverick

Object Pool Design Pattern in Go

The Object Pool Design Pattern is a creational design pattern in which a pool of objects is initialized and created beforehand and kept in a pool. As and when needed, a client can request an object from the pool, use it, and return it to the pool. The object in the pool is never destroyed.

When to Use:

  • When the cost to create the object of the class is high and the number of such objects that will be needed at a particular time is not much.

    • Let’s take the example of DB connections. Each of the connection object creation is cost is high as there is network calls involved and also at a time not more than a certain connection might be needed. The object pool design pattern is perfectly suitable for such cases.
  • When the pool object is the immutable object

    • Again take the example of DB connection again. A DB connection is an immutable object. Almost none of its property needs to be changed
  • For performance reasons. It will boost the application performance significantly since the pool is already created

Prototype Pattern in Go

It is a creational design pattern that lets you create copies of objects. In this pattern, the responsibility of creating the clone objects is delegated to the actual object to clone.

The object to be cloned exposes a clone method which returns a clone copy of the object

When to Use

  • We use prototype pattern when the object to be cloned creation process is complex i.e the cloning may involve vases of handling deep copies, hierarchical copies, etc. Moreover, there may be some private members too which cannot be directly accessed.
  • A copy of the object is created instead of creating a new instance from scratch. This prevents costly operations involved while creating a new object such as database operation.
  • When you want to create a copy of a new object, but it is only available to you as an interface. Hence you cannot directly create copies of that object.

Singleton Pattern in Go

Singleton Design Pattern is a creational design pattern and also one of the most commonly used design pattern. This pattern is used when only a single instance of the struct should exist. This single instance is called a singleton object. Some of the cases where the singleton object is applicable:

  • DB instance – we only want to create only one instance of DB object and that instance will be used throughout the application.
  • Logger instance – again only one instance of the logger should be created and it should be used throughout the application.

Behavioural Design Pattern

Observer Design Pattern in Go

Observer Design Pattern is a behavioral design pattern. This pattern allows an instance (called subject) to publish events to other multiple instances (called observers). These observers subscribe to the subject and hence get notified by events in case of any change happening in the subject.

Let’s take an example. In the E-Commerce website, many items go out of stock. There can be customers, who are interested in a particular item that went out of stock. There are three solutions to this problem

  1. The customer keeps checking the availability of the item at some frequency.
  2. E-Commerce bombard customers with all new items available which are in stock
  3. The customer subscribes only to the particular item he is interested in and gets notified in the case that item is available. Also, multiple customers can subscribe to the same product

Strategy pattern

Strategy pattern is a behavioral design pattern. Strategy pattern allows changing the behavior of an object at the runtime which is useful in certain cases.

https://golangbyexample.com/facade-design-pattern-in-golang/

Facade Design Pattern in Go:

Facade Pattern is classified as a structural design pattern. This design pattern is meant to hide the complexities of the underlying system and provide a simple interface to the client. It provides a unified interface to underlying many interfaces in the system so that from the client perspective it is easier to use. Basically it provides a higher level abstraction over a complicated system.

Check Account
Check Security Pin
Credit/Debit Balance
Make Ledger Entry
Send Notification

As can be noticed, there are a lot of things that happen for a single debit/credit operation. This is where the Facade pattern comes into picture. As a client one only needs to enter the Wallet Number, Security Pin, Amount and specify the type of operation. The rest of the things are taken care of in the background. Here we create a WalletFacade which provides a simple interface to the client and which takes care of dealing with all underlying operations

Structural Design Pattern:

Adapter Patern:

Adapter is a structural design pattern, which allows incompatible objects to collaborate.

The adapter pattern is a design pattern that allows the interface of a class to be used as another interface.

This is a frequently used pattern in ORM libraries (ActiveRecord, GORM, etc), because it allows for connections and queries to different data backends (databases) while keeping the same client interface.

Another common occurrence of this pattern is in hardware drivers. Take printers for instance. Most printers can be used either via USB or serial connections or over the network

Example:

We have a client code that expects some features of an object (Lightning port), but we have another object called adaptee (Windows laptop) which offers the same functionality but through a different interface (USB port)

Bridge in Go

Bridge is a structural design pattern that divides business logic or huge class into separate class hierarchies that can be developed independently.

One of these hierarchies (often called the Abstraction) will get a reference to an object of the second hierarchy (Implementation). The abstraction will be able to delegate some (sometimes, most) of its calls to the implementations object. Since all implementations will have a common interface, they’d be interchangeable inside the abstraction.

Example:

Say, you have two types of computers: Mac and Windows. Also, two types of printers: Epson and HP. Both computers and printers need to work with each other in any combination. The client doesn’t want to worry about the details of connecting printers to computers.

If we introduce new printers, we don’t want our code to grow exponentially. Instead of creating four structs for the 2*2 combination, we create two hierarchies:

Abstraction hierarchy: this will be our computers
Implementation hierarchy: this will be our printers
These two hierarchies communicate with each other via a Bridge, where the Abstraction (computer) contains a reference to the Implementation (printer). Both the abstraction and implementation can be developed independently without affecting each other.

See the example code https://refactoring.guru/design-patterns/bridge/go/example

Composite in Go

Composite is a structural design pattern that allows composing objects into a tree-like structure and work with the it as if it was a singular object.

Composite became a pretty popular solution for the most problems that require building a tree structure. Composite’s great feature is the ability to run methods recursively over the whole tree structure and sum up the results.

Example
Let’s try to understand the Composite pattern with an example of an operating system’s file system. In the file system, there are two types of objects: files and folders. There are cases when files and folders should be treated to be the same way. This is where the Composite pattern comes in handy.

Imagine that you need to run a search for a particular keyword in your file system. This search operation applies to both files and folders. For a file, it will just look into the contents of the file; for a folder, it will go through all files of that folder to find that keyword.

Top comments (0)