Design Patterns in Golang - Part-2

Published 10-12-2017 00:00:00

Structural Patterns

Decorator Pattern

Decorator structural pattern allows extending the function of an existing object dynamically without altering its internals.

Decorators provide a flexible method to extend functionality of objects.

Implementation

LogDecorate decorates a function with the signature func(int) int that manipulates integers and adds input/output logging capabilities.

type Object func(int) int

func LogDecorate(fn Object) Object {
	return func(n int) int {
		log.Println("Starting the execution with the integer", n)

		result := fn(n)

		log.Println("Execution is completed with the result", result)

        return result
	}
}
Usage
func Double(n int) int {
    return n * 2
}

f := LogDecorate(Double)

f(5)
// Starting execution with the integer 5
// Execution is completed with the result 10
Rules of Thumb
  • Unlike Adapter pattern, the object to be decorated is obtained by injection.
  • Decorators should not alter the interface of an object.

Proxy Pattern

The proxy pattern provides an object that controls access to another object, intercepting all calls.

Implementation

The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate.

Short idea of implementation:

    // To use proxy and to object they must implement same methods
    type IObject interface {
        ObjDo(action string)
    }

    // Object represents real objects which proxy will delegate data
    type Object struct {
        action string
    }

    // ObjDo implements IObject interface and handel's all logic
    func (obj *Object) ObjDo(action string) {
        // Action behavior
        fmt.Printf("I can, %s", action)
    }

    // ProxyObject represents proxy object with intercepts actions
    type ProxyObject struct {
        object *Object
    }

    // ObjDo are implemented IObject and intercept action before send in real Object
    func (p *ProxyObject) ObjDo(action string) {
        if p.object == nil {
            p.object = new(Object)
        }
        if action == "Run" {
            p.object.ObjDo(action) // Prints: I can, Run
        }
    }

Usage

More complex usage of proxy as example: User creates “Terminal” authorizes and PROXY send execution command to real Terminal object See proxy/main.go or view in the Playground.