This repository is to capture not only design patterns in action but also any complex patterns in Golang. I'm sharing this as a starting point for others to learn Go patterns and experiment with them, and also to gather feedback on what we can improve. If you have a suggestion, feel free to file an issue.
-
To enforce at compile time all methods inside interface should be implemented.
type ShapeCalculator interface { Area() int Perimeter() int } type Rectangle struct { Width int Height int } // following line guarantee that struct `Rectangle` must have to implement all methods of interface `ShapeCalculator`. // purpose of this pattern is to enforce at compile time that `*Rectangle` implements the interface. var _ ShapeCalculator = (*Rectangle)(nil) // another way of using this var _ ShapeCalculator = &Rectangle{}
-
Another pattern of using interface
type Action interface { // Do performs an action. Do(ctx context.Context) } // ActionFunc is a function that implements Action. type ActionFunc func(ctx context.Context) // Do performs an action. func (f ActionFunc) Do(ctx context.Context) { f(ctx) }
-
Define an interface for creating an object, but let subclasses/Methods decide which class to instantiate. Defer the instantiation to subclasses/Methods. check example here.
-
Define
Factoryinterface. -
Defer the instantiation of object to subclasses/Methods.
type Factory interface { NewPerson() *person NewAgent() *secretAgent } // create object of factory fact := factory.NewFactory(config) // with factory method, we can construct the instances of both person/agent. person := fact.NewPerson() agent := fact.NewAgent()
-
-
It's a creational design pattern that separate the construction of a complex object or segregating the one builder into multiple builders. It is used to construct a complex object step by step and the final step will return the object. Check example here.
// instead of passing all parameters at once via constructor to create object, we can use builder pattern to create object step by step. emp1 := dev.SetName("Ishan").SetTechStack([]string{"C++", "Docker", "Go"}).SetEmpID(2).BuildDev()
-
It's creational desing pattern that ensures that a class has only one instance and provides a global point of access to it. This is useful when exactly one object is needed to coordinate actions across a system. Check example here.
type Singleton struct { // Your singleton fields } var ( instance *Singleton once sync.Once ) func GetInstance() *Singleton { once.Do(func() { instance = &Singleton{ // ... } }) return instance }
Note
Always use sync.Once in Go for thread safe.
-
It's a structural design pattern that allows you to dynamically add new behavior to existing objects by placing them inside special wrapper objects. check example here.
// Base existing object type Book struct { ... } // Decorator which wraps the original base object type BorrowableBook struct { Book // Embed the original object IsBorrowed bool ... } // Adds new behavior "Borrow()" using decorator object func (b *BorrowableBook) Borrow() { if b.IsBorrowed { ... } ... }
-
It's a structural design pattern that act as a interface or middleman for another object to control access to it. A proxy can be interface to anything: a network connection, delay in expensive object creation etc. check example here.
type Database interface { Query(string) string } type RealDatabase struct { // Database fields } func (db *RealDatabase) Query(query string) string { // query directly access to db } // ---- Proxy ---- type DatabaseProxy struct { db *RealDatabase cache map[string]string } // Client can only call DatabaseProxy's Query as only proxy method object creation is possible. func (p *DatabaseProxy) Query(query string) string { // this method act as middleman for quering the db with custom functionality can be added like cache etc. }
Note
The difference b/w decorator and proxy pattern is decorator add more features to object whereas proxy manages how/when object is accessed.