DEV Community

loading...
Gopher

Go All Design Patterns Code with Workflow

Javad Rajabzade
Software engineer
・13 min read

Behavioral Patterns


Design Pattern Command

Design Pattern Command
Design Pattern Command

import (
    "fmt"
)

//Command type
type Command interface {
    Execute()
}

//BankClient is Invoker
type BankClient struct {
    putCommand Command
    getCommand Command
}

//PutMoney runs the putCommand
func (bc BankClient) PutMoney() {
    bc.putCommand.Execute()
}

//GetMoney runs the getCommand
func (bc BankClient) GetMoney() {
    bc.getCommand.Execute()
}

//Bank is Receiver
type Bank struct{}

func (b Bank) giveMoney() {
    fmt.Println("money to the client")
}

func (b Bank) receiveMoney() {
    fmt.Println("money from the client")
}

//PutCommand is ConcreteCommand
type PutCommand struct {
    bank Bank
}

//Execute command
func (pc PutCommand) Execute() {
    pc.bank.receiveMoney()
}

//GetCommand is ConcreteCommand
type GetCommand struct {
    bank Bank
}

//Execute command
func (gc GetCommand) Execute() {
    gc.bank.giveMoney()
}

//Client
bank := Bank{}
cPut := PutCommand{bank}
cGet := GetCommand{bank}
client := BankClient{cPut, cGet}
client.GetMoney()
//printed: money to the client
client.PutMoney()
//printed: money from the client
Enter fullscreen mode Exit fullscreen mode

Design Pattern Interpreter

Design Pattern Interpreter
Design Pattern Interpreter

import (
    "fmt"
)

//Expression is AbstractExpression
type Expression interface {
    Interpret(i int) bool
}

//DivExpression is TerminalExpression
type DivExpression struct {
    divider int
}

//Interpret func calculates expression
func (e DivExpression) Interpret(i int) bool {
    return i%e.divider == 0
}

//OrExpression is NonterminalExpression
type OrExpression struct {
    exp1 Expression
    exp2 Expression
}

//Interpret func calculates expression
func (e OrExpression) Interpret(i int) bool {
    return e.exp1.Interpret(i) || e.exp2.Interpret(i)
}

//AndExpression is NonterminalExpression
type AndExpression struct {
    exp1 Expression
    exp2 Expression
}

//Interpret func calculates expression
func (e AndExpression) Interpret(i int) bool {
    return e.exp1.Interpret(i) && e.exp2.Interpret(i)
}

//Client
divExp5 := DivExpression{5}
divExp7 := DivExpression{7}
orExp := OrExpression{
    divExp5, divExp7}
andExp := AndExpression{
    divExp5, divExp7}

//21 is divided by 7 or 5?
result1 := orExp.Interpret(21)
//result1 is true

//21 is divided by 7 and 5?
result2 := andExp.Interpret(21)
//result2 is false

//35 is divided by 7 and 5?
result3 := andExp.Interpret(35)
//result3 is true

fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
Enter fullscreen mode Exit fullscreen mode

Design Pattern Iterator

Design Pattern Iterator
Design Pattern Iterator

import (
    "fmt"
)

//IntIterator is Iterator
type IntIterator interface {
    First()
    Next()
    IsDone() bool
    CurrentItem() int
}

//Numbers is ConcreteAggregate
type Numbers struct {
    Data []int
}

//GetIterator return Iterator
func (n Numbers) GetIterator() IntIterator {
    return &Iterator{n, 0}
}

//Iterator is ConcreteIterator
type Iterator struct {
    _numbers Numbers
    _index   int
}

//First positions the iterator to the first element
func (i *Iterator) First() {
    i._index = 0
}

//Next advances the current element
func (i *Iterator) Next() {
    i._index++
}

//IsDone checks whether the index refers to an element withinthe List
func (i *Iterator) IsDone() bool {
    return i._index >= len(i._numbers.Data)
}

//CurrentItem returns the item at the current index
func (i *Iterator) CurrentItem() int {
    return i._numbers.Data[i._index]
}

//Client
numbers := Numbers{[]int{2, 3, 5, 7, 11}}
iterator := numbers.GetIterator()
sum := 0
for iterator.First(); !iterator.IsDone(); iterator.Next() {
    sum += iterator.CurrentItem()
}
//sum is 28
Enter fullscreen mode Exit fullscreen mode

Design Pattern Mediator

Design Pattern Mediator
Design Pattern Mediator

//Mediator defines an interface for communicating with Colleague objects
type Mediator interface {
    Sync(switcher *Switcher)
    Add(switcher *Switcher)
}

//Switcher is Colleague
type Switcher struct {
    State     bool
    _mediator Mediator
}

//NewSwitcher creates a new Switcher
func NewSwitcher(mediator Mediator) *Switcher {
    switcher := &Switcher{false, mediator}
    mediator.Add(switcher)
    return switcher
}

//Sync starts the mediator Sync function
func (s Switcher) Sync() {
    s._mediator.Sync(&s)
}

//SyncMediator is ConcreteMediator
type SyncMediator struct {
    Switchers []*Switcher
}

//Sync synchronizes the state of all Colleague objects
func (sm *SyncMediator) Sync(switcher *Switcher) {
    for _, curSwitcher := range sm.Switchers {
        curSwitcher.State = switcher.State
    }
}

//Add append Colleague to the Mediator list
func (sm *SyncMediator) Add(switcher *Switcher) {
    sm.Switchers = append(sm.Switchers, switcher)
}

//Client
mediator := &SyncMediator{[]*Switcher{}}
switcher1 := NewSwitcher(mediator)
switcher2 := NewSwitcher(mediator)
switcher3 := NewSwitcher(mediator)

switcher1.State = true
state2 := switcher2.State
//state2 is false
state3 := switcher3.State
//state3 is false

switcher1.Sync()
state2 = switcher2.State
//state2 is true
state3 = switcher3.State
//state3 is true
Enter fullscreen mode Exit fullscreen mode

Design Pattern Memento

Design Pattern Memento
Design Pattern Memento

//Point is State
type Point struct {
    X, Y int
}

//Memento contains a State field
type Memento struct {
    _state Point
}

func (m Memento) getState() Point {
    return m._state
}

//Shape is Originator
type Shape struct {
    Position Point
}

//Move Shape
func (s *Shape) Move(left, top int) {
    s.Position.X += left
    s.Position.Y += top
}

func (s *Shape) getMemento() Memento {
    state := Point{
    s.Position.X, s.Position.Y}
    return Memento{state}
}

func (s *Shape) setMemento(memento Memento) {
    s.Position = memento.getState()
}

//ShapeHelper is Caretaker
type ShapeHelper struct {
    _shape *Shape
    _stack []Memento
}

//NewShapeHelper creates a new ShapeHelper
func NewShapeHelper(shape *Shape) ShapeHelper {
    return ShapeHelper{shape, []Memento{}}
}

//Move Shape and save prior state
func (sh *ShapeHelper) Move(left, top int) {
    sh._stack = append(
        sh._stack, sh._shape.getMemento())
    sh._shape.Move(left, top)
}

//Undo move shape to previous position
func (sh *ShapeHelper) Undo() {
    l := len(sh._stack)
    if l > 0 {
        memento := sh._stack[l-1]
        sh._stack = sh._stack[:l-1]
        sh._shape.setMemento(memento)
    }
}

//Client
shape := &Shape{}
helper := NewShapeHelper(shape)

helper.Move(2, 3)
//shape.Position is (2, 3)
helper.Move(-5, 4)
//shape.Position is (-3, 7)

helper.Undo()
//shape.Position is (2, 3)
helper.Undo()
//shape.Position is (0, 0)
Enter fullscreen mode Exit fullscreen mode

Design Pattern Observer

Design Pattern Observer
Design Pattern Observer

import (
    "fmt"
)

type observer interface {
    update(state string)
}

//TextObserver is ConcreteObserver
type TextObserver struct {
    _name string
}

func (t TextObserver) update(state string) {
    fmt.Println(t._name + ": " + state)
}

//TestSubject is Subject
type TestSubject struct {
    _observers []observer
}

//Attach adds an observer
func (ts *TestSubject) Attach(observer observer) {
    ts._observers = append(ts._observers, observer)
}

//Detach removes an observer
func (ts *TestSubject) Detach(observer observer) {
    index := 0
    for i := range ts._observers {
        if ts._observers[i] == observer {
            index = i
            break
        }
    }
    ts._observers = append(ts._observers[0:index], ts._observers[index+1:]...)
}

func (ts TestSubject) notify(state string) {
    for _, observer := range ts._observers {
        observer.update(state)
    }
}

//TextEdit is ConcreteSubject
type TextEdit struct {
    TestSubject
    Text string
}

//SetText changes the text and informs observers
func (te TextEdit) SetText(text string) {
    te.Text = text
    te.TestSubject.notify(text)
}

//Client
observer1 := TextObserver{"IObserver #1"}
observer2 := TextObserver{"IObserver #2"}

textEdit := TextEdit{}
textEdit.Attach(observer1)
textEdit.Attach(observer2)

textEdit.SetText("test text")
//printed:
//IObserver #1: test text
//IObserver #2: test text
Enter fullscreen mode Exit fullscreen mode

Design Pattern State

Design Pattern State
Design Pattern State

import (
    "fmt"
)

type state interface {
    open(c *Connection)
    close(c *Connection)
}

//CloseState is ConcreteState
type CloseState struct{}

func (cs CloseState) open(c *Connection) {
    fmt.Println("open the connection")
    c.setState(OpenState{})
}

func (cs CloseState) close(c *Connection) {
    fmt.Println("connection is already closed")
}

//OpenState is ConcreteState
type OpenState struct{}

func (os OpenState) open(c *Connection) {
    fmt.Println("connection is already open")
}

func (os OpenState) close(c *Connection) {
    fmt.Println("close the connection")
    c.setState(CloseState{})
}

//Connection is Context
type Connection struct {
    _state state
}

//Open connection
func (c *Connection) Open() {
    c._state.open(c)
}

//Close connection
func (c *Connection) Close() {
    c._state.close(c)
}

func (c *Connection) setState(state state) {
    c._state = state
}

//Client
con := Connection{CloseState{}}
con.Open()
//printed: open the connection
con.Open()
//printed: connection is already open
con.Close()
//printed: close the connection
con.Close()
//printed: connection is already closed
Enter fullscreen mode Exit fullscreen mode

Design Pattern Strategy

Design Pattern Strategy
Design Pattern Strategy

import (
    "fmt"
)

//Strategy with integer operation
type Strategy interface {
    DoOperation(a int, b int) int
}

//AddStrategy is ConcreteStrategy
type AddStrategy struct{}

//DoOperation is integer addition function
func (s AddStrategy) DoOperation(a int, b int) int {
    return a + b
}

//SubstractStrategy is ConcreteStrategy
type SubstractStrategy struct{}

//DoOperation is integer subtraction function
func (s SubstractStrategy) DoOperation(a int, b int) int {
    return a - b
}

//Calc is Context
type Calc struct {
    _strategy Strategy
}

//Execute current strategy
func (c Calc) Execute(a int, b int) int {
    if c._strategy == nil {
        return 0
    }

    return c._strategy.DoOperation(a, b)
}

//SetStrategy changes the current strategy
func (c *Calc) SetStrategy(strategy Strategy) {
    c._strategy = strategy
}

//Client
calc := Calc{}
result1 := calc.Execute(5, 3)
//result1 is 0

calc.SetStrategy(AddStrategy{})
result2 := calc.Execute(5, 3)
//result2 is 8

calc.SetStrategy(SubstractStrategy{})
result3 := calc.Execute(5, 3)
//result3 is 2

fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
Enter fullscreen mode Exit fullscreen mode

Design Pattern Visitor

Design Pattern Visitor
Design Pattern Visitor

import (
    "fmt"
    "strconv"
)

//Element interface
type Element interface {
    Accept(v CarVisitor)
}

//Engine is ConcreteElement
type Engine struct{}

//Accept operation that takes a visitor as an argument
func (e Engine) Accept(v CarVisitor) {
    v.visitEngine(e)
}

//Wheel is ConcreteElement
type Wheel struct {
    Number int
}

//Accept operation
func (w Wheel) Accept(v CarVisitor) {
    v.visitWheel(w)
}

//Car is ConcreteElement
type Car struct {
    _items []Element
}

//Accept operation
func (c Car) Accept(v CarVisitor) {
    for _, e := range c._items {
        e.Accept(v)
    }
    v.visitCar(c)
}

//CarVisitor is Visitor
type CarVisitor interface {
    visitEngine(engine Engine)
    visitWheel(wheel Wheel)
    visitCar(car Car)
}

//TestCarVisitor is ConcreteVisitor
type TestCarVisitor struct{}

func (v TestCarVisitor) visitEngine(engine Engine) {
    fmt.Println("test engine")
}

func (v TestCarVisitor) visitWheel(wheel Wheel) {
    fmt.Println("test wheel #" +
        strconv.Itoa(wheel.Number))
}

func (v TestCarVisitor) visitCar(car Car) {
    fmt.Println("test car")
}

//RepairCarVisitor is ConcreteVisitor
type RepairCarVisitor struct{}

func (v RepairCarVisitor) visitEngine(engine Engine) {
    fmt.Println("repair engine")
}

func (v RepairCarVisitor) visitWheel(wheel Wheel) {
    fmt.Println("repair wheel #" +
        strconv.Itoa(wheel.Number))
}

func (v RepairCarVisitor) visitCar(car Car) {
    fmt.Println("repair car")
}

//Client
car := Car{[]Element{
        Engine{},
        Wheel{1},
        Wheel{2},
        Wheel{3},
        Wheel{4},
}}
v1 := TestCarVisitor{}
v2 := RepairCarVisitor{}

car.Accept(v1)
car.Accept(v2)
Enter fullscreen mode Exit fullscreen mode

Creational Patterns


Design Pattern Abstract Factory

Design Pattern Abstract Factory
Design Pattern Abstract Factory

import (
    "fmt"
)

//ProductA is abstract product A
type ProductA interface {
    TestA()
}

//ProductB is abstract product B
type ProductB interface {
    TestB()
}

//Factory is abstract factory
type Factory interface {
    CreateA() ProductA
    CreateB() ProductB
}

//ProductA1 is concrete product A1
type ProductA1 struct{}

//TestA is implementation of the ProductA interface method
func (p ProductA1) TestA() {
    fmt.Println("test A1")
}

//ProductB1 is concrete product B1
type ProductB1 struct{}

//TestB is implementation of the ProductB interface method
func (p ProductB1) TestB() {
    fmt.Println("test B1")
}

//ProductA2 is concrete product A2
type ProductA2 struct{}

//TestA is implementation of the ProductA interface method
func (p ProductA2) TestA() {
    fmt.Println("test A2")
}

//ProductB2 is concrete product B2
type ProductB2 struct{}

//TestB is implementation of the ProductB interface method
func (p ProductB2) TestB() {
    fmt.Println("test B2")
}

//Factory1 is concrete factory 1
type Factory1 struct{}

//CreateA is implementation of the Factory interface method
func (f Factory1) CreateA() ProductA {
    return ProductA1{}
}

//CreateB is implementation of the Factory interface method
func (f Factory1) CreateB() ProductB {
    return ProductB1{}
}

//Factory2 is concrete factory 2
type Factory2 struct{}

//CreateA is implementation of the Factory interface method
func (f Factory2) CreateA() ProductA {
    return ProductA2{}
}

//CreateB is implementation of the Factory interface method
func (f Factory2) CreateB() ProductB {
    return ProductB2{}
}

//client code:

//TestFactory creates and tests factories
func TestFactory(factory Factory) {
    productA := factory.CreateA()
    productB := factory.CreateB()
    productA.TestA()
    productB.TestB()
}

TestFactory(Factory1{})
//printed: test A1
//         test B1
TestFactory(Factory2{})
//printed: test A2
//         test B2
Enter fullscreen mode Exit fullscreen mode

Design Pattern Builder

Design Pattern Builder
Design Pattern Builder

import (
    "fmt"
)

//TextWorker is AbstractBuilder
type TextWorker interface {
    AddText(text string)
    AddNewLine(text string)
}

//TextBuilder is ConcreteBuilder 1
type TextBuilder struct {
    Text string
}

//AddText adds text to the current line 
func (tb *TextBuilder) AddText(text string) {
    tb.Text += text
}

//AddNewLine adds new line 
func (tb *TextBuilder) AddNewLine(text string) {
    tb.Text += ("\n" + text)
}

//HTMLBuilder is ConcreteBuilder 2
type HTMLBuilder struct {
    HTML string
}

//AddText adds span to the current line 
func (tb *HTMLBuilder) AddText(text string) {
    tb.HTML += ("<span>" + text + "</span>")
}

//AddNewLine adds new line 
func (tb *HTMLBuilder) AddNewLine(text string) {
    tb.HTML += "<br/>\n"
    tb.AddText(text)
}

//TextMaker is Director
type TextMaker struct{}

//MakeText fills the text
func (tm TextMaker) MakeText(textBuilder TextWorker) {
    textBuilder.AddText("line 1")
    textBuilder.AddNewLine("line 2")
}

//Client
textMaker := TextMaker{}

textBuilder := TextBuilder{}
textMaker.MakeText(&textBuilder)
text := textBuilder.Text
//text: line 1
//      line 2

htmlBuilder := HTMLBuilder{}
textMaker.MakeText(&htmlBuilder)
html := htmlBuilder.HTML
//html: <span>line 1</span><br/>
//      <span>line 2</span>

fmt.Println(text)
fmt.Println(html)
Enter fullscreen mode Exit fullscreen mode

Design Pattern Factory Method

Design Pattern Factory Method
Design Pattern Factory Method

import (
    "fmt"
)

//Employee is Product
type Employee interface {
    Test()
}

//Booker is ConcreteProduct
type Booker struct{}

//Test is Employee method
func (e Booker) Test() {
    fmt.Println("Booker")
}

//Manager is ConcreteProduct
type Manager struct{}

//Test is Manager method
func (e Manager) Test() {
    fmt.Println("Manager")
}

//BookerCreator is ConcreteCreator
type BookerCreator struct{}

//CreateEmployee creates an Booker
func (c BookerCreator) CreateEmployee() Employee {
    return Booker{}
}

//ManagerCreator is ConcreteCreator
type ManagerCreator struct {}

//CreateEmployee creates an Manager
func (c ManagerCreator) CreateEmployee() Employee {
    return Manager{}
}

//Client
booker := BookerCreator{}.CreateEmployee()
booker.Test()
//printed: Booker

manager := ManagerCreator{}.CreateEmployee()
manager.Test()
//printed: Manager
Enter fullscreen mode Exit fullscreen mode

Design Pattern Prototype

Design Pattern Prototype
Design Pattern Prototype

import (
    "fmt"
)

//Shape is Prototype
type Shape interface {
    Clone() Shape
}

//Square is ConcretePrototype
type Square struct {
    LineCount int
}

//Clone creates a copy of the square
func (s Square) Clone() Shape {
    return Square{s.LineCount}
}

//Client

//ShapeMaker contains a Shape
type ShapeMaker struct {
    Shape Shape
}

//MakeShape creates a copy of the Shape
func (sm ShapeMaker) MakeShape() Shape {
    return sm.Shape.Clone()
}

square := Square{4}
maker := ShapeMaker{square}

square1 := maker.MakeShape()
square2 := maker.MakeShape()

fmt.Println(square1)
fmt.Println(square2)
Enter fullscreen mode Exit fullscreen mode

Design Pattern Singleton

Design Pattern Singleton
Design Pattern Singleton

package settings

//Settings is simple struct
type Settings struct {
    Port int
    Host string
}

var instance *Settings

//GetInstance returns a single instance of the settings
func GetInstance() *Settings {
    if instance == nil {
        instance = &Settings{} // <--- NOT THREAD SAFE
    }
    return instance
}

//Client
import (
    "fmt"
    Settings "../CreationalPatterns/Singleton"
)

settings := Settings.GetInstance()

settings.Host = "192.168.100.1"
settings.Port = 33

settings1 := Settings.GetInstance()
//settings1.Port is 33
Enter fullscreen mode Exit fullscreen mode

Structural Patterns


Design Pattern Adapter (composition)

Design Pattern Adapter
Design Pattern Adapter

import (
    "fmt"
    "strings"
)

//StringList is Adaptee
type StringList struct {
    rows []string
}

func (sl StringList) getString() string {
    return strings.Join(sl.rows, "\n")
}

func (sl *StringList) add(value string) {
    sl.rows = append(sl.rows, value)
}

//TextAdapter is Adapter
type TextAdapter struct {
    RowList StringList
}

func (ta TextAdapter) getText() string {
    return ta.RowList.getString()
}

func getTextAdapter() TextAdapter {
    rowList := StringList{}
    rowList.add("line 1")
    rowList.add("line 2")
    adapter := TextAdapter{rowList}
    return adapter
}

//Client
adapter := getTextAdapter()
text := adapter.getText()
//text: line 1
//      line 2

fmt.Println(text)
Enter fullscreen mode Exit fullscreen mode

Design Pattern Adapter (inheritance)

Design Pattern Adapter
Design Pattern Adapter

import (
    "fmt"
    "strings"
)

//StringList is Adaptee
type StringList struct {
    rows []string
}

func (sl StringList) getString() string {
    return strings.Join(sl.rows, "\n")
}

func (sl *StringList) add(value string) {
    sl.rows = append(sl.rows, value)
}

//TextAdapter is Adapter
type TextAdapter struct {
    StringList
}

func (ta TextAdapter) getText() string {
    return ta.getString()
}

func getTextAdapter() TextAdapter {
    adapter := TextAdapter{}
    adapter.add("line 1")
    adapter.add("line 2")
    return adapter
}

//Client
adapter := getTextAdapter()
text := adapter.getText()
//text: line 1
//      line 2

fmt.Println(text)
Enter fullscreen mode Exit fullscreen mode

Design Pattern Bridge

Design Pattern Bridge
Design Pattern Bridge

import (
    "fmt"
    "strings"
)

//AText is Abstraction
type AText interface {
    getText() string
    addLine(value string)
}

//ITextImp is abstract Implementator
type ITextImp interface {
    getString() string
    appendLine(value string)
}

//TextImp is Implementator
type TextImp struct {
    rows []string
}

func (ti TextImp) getString() string {
    return strings.Join(ti.rows, "\n")
}

//TextMaker RefinedAbstraction
type TextMaker struct {
    textImp ITextImp
}

func (tm TextMaker) getText() string {
    return tm.textImp.getString()
}

func (tm TextMaker) addLine(value string) {
    tm.textImp.appendLine(value)
}

//TextBuilder is ConcreteImplementator1
type TextBuilder struct {
    TextImp
}

func (tb *TextBuilder) appendLine(value string) {
    tb.rows = append(tb.rows, value)
}

//HTMLBuilder is ConcreteImplementator2
type HTMLBuilder struct {
    TextImp
}

func (hb *HTMLBuilder) appendLine(value string) {
    hb.rows = append(hb.rows,
        "<span>"+value+"</span><br/>")
}

func fillTextBuilder(textImp ITextImp) AText {
    textMaker := TextMaker{textImp}
    textMaker.addLine("line 1")
    textMaker.addLine("line 2")
    return textMaker
}

//Client
textMaker := fillTextBuilder(&TextBuilder{})
text := textMaker.getText()
//test: line 1
//      line 2

htmlMaker := fillTextBuilder(&HTMLBuilder{})
html := htmlMaker.getText()
//html: <span>line 1</span><br/>
//      <span>line 2</span><br/>

fmt.Println(text)
fmt.Println(html)
Enter fullscreen mode Exit fullscreen mode

Design Pattern Composite

Design Pattern Composite
Design Pattern Composite

import (
    "fmt"
)

//Graphic is Component
type Graphic interface {
    Draw()
}

//Сircle is Leaf
type Сircle struct{}

//Draw is Operation
func (c Сircle) Draw() {
    fmt.Println("Draw circle")
}

//Square is Leaf
type Square struct{}

//Draw is Operation
func (s Square) Draw() {
    fmt.Println("Draw square")
}

//Image is Composite
type Image struct {
    graphics []Graphic
}

//Add Adds a Leaf to the Composite.
func (i *Image) Add(graphic Graphic) {
    i.graphics = append(i.graphics, graphic)
}

//Draw is Operation
func (i Image) Draw() {
    fmt.Println("Draw image")
    for _, g := range i.graphics {
        g.Draw()
    }
}

//Client
image := Image{}
image.Add(Сircle{})
image.Add(Square{})
picture := Image{}
picture.Add(image)
picture.Add(Image{})
picture.Draw()
Enter fullscreen mode Exit fullscreen mode

Design Pattern Decorator

Design Pattern Decorator
Design Pattern Decorator

import (
    "fmt"
)

//Shape is Component
type Shape interface {
    ShowInfo()
}

//Square is ConcreteComponent
type Square struct{}

//ShowInfo is Operation()
func (s Square) ShowInfo() {
    fmt.Print("square")
}

//ShapeDecorator is Decorator
type ShapeDecorator struct {
    Shape Shape
}

//ShowInfo is Operation()
func (sd ShapeDecorator) ShowInfo() {
    sd.Shape.ShowInfo()
}

//ColorShape is ConcreteDecorator
type ColorShape struct {
    ShapeDecorator
    color string
}

//ShowInfo is Operation()
func (cs ColorShape) ShowInfo() {
    fmt.Print(cs.color + " ")
    cs.Shape.ShowInfo()
}

//ShadowShape is ConcreteDecorator
type ShadowShape struct {
    ShapeDecorator
}

//ShowInfo is Operation()
func (ss ShadowShape) ShowInfo() {
    ss.Shape.ShowInfo()
    fmt.Print(" with shadow")
}

//Client
square := Square{}
square.ShowInfo()
//printed: square
fmt.Println()

colorShape := ColorShape{
    ShapeDecorator{square}, "red"}
colorShape.ShowInfo()
//printed: red square
fmt.Println()

shadowShape := ShadowShape{
ShapeDecorator{colorShape}}
shadowShape.ShowInfo()
//printed: red square with shadow
Enter fullscreen mode Exit fullscreen mode

Design Pattern Facade

Design Pattern Facade
Design Pattern Facade

import (
    "fmt"
)

//Complex parts
type kettle struct{}

func (k kettle) TurnOff() {
    fmt.Println("Kettle turn off")
}

type toaster struct{}

func (t toaster) TurnOff() {
    fmt.Println("Toaster turn off")
}

type refrigerator struct{}

func (r refrigerator) TurnOff() {
    fmt.Println("Refrigerator turn off")
}

//Facade
type kitchen struct {
    kettle       kettle
    toaster      toaster
    refrigerator refrigerator
}

func (k kitchen) Off() {
    k.kettle.TurnOff()
    k.toaster.TurnOff()
    k.refrigerator.TurnOff()
}

//Client
kitchen := kitchen{
    kettle{},
    toaster{},
    refrigerator{},
}

kitchen.Off()
Enter fullscreen mode Exit fullscreen mode

Design Pattern Flyweight

Design Pattern Flyweight
Design Pattern Flyweight

import (
    "fmt"
)

//Span is Flyweight
type Span interface {
    PrintSpan(style string)
}

//Char is ConcreteFlyweight
type Char struct {
    C rune
}

//PrintSpan is Operation(extrinsicState)
func (c Char) PrintSpan(style string) {
    fmt.Println("<span style=\"" +
        style + "\">" + string(c.C) + "</span>")
}

//CharFactory is FlyweightFactory
type CharFactory struct {
    chars map[rune]Char
}

//GetChar is GetFlyweight(key)
func (cf *CharFactory) GetChar(c rune) Span {
    if value, exists := cf.chars[c]; exists {
        return value
    }
    char := Char{c}
    cf.chars[c] = char
    return char
}

//Client
factory := CharFactory{map[rune]Char{}}
charA := factory.GetChar('A')
charA.PrintSpan("font-size: 12")

charB := factory.GetChar('B')
charB.PrintSpan("font-size: 12")

charA1 := factory.GetChar('A')
charA1.PrintSpan("font-size: 12")

equal := charA == charA1
//equal is true

fmt.Println(equal)
Enter fullscreen mode Exit fullscreen mode

Design Pattern Proxy

Design Pattern Proxy
Design Pattern Proxy

import (
    "fmt"
)

//Graphic is Subject
type Graphic interface {
    Draw()
}

//Image is RealSubjec
type Image struct {
    FileName string
}

//Draw is Request()
func (im Image) Draw() {
    fmt.Println("draw " + im.FileName)
}

//ImageProxy is Proxy
type ImageProxy struct {
    FileName string
    _image   *Image
}

//GetImage creates an Subject
func (ip ImageProxy) GetImage() *Image {
    if ip._image == nil {
        ip._image = &Image{ip.FileName}
    }
    return ip._image
}

//Draw is Request()
func (ip ImageProxy) Draw() {
    ip.GetImage().Draw()
}

//Client
proxy := ImageProxy{FileName: "1.png"}
//operation without creating a RealSubject
fileName := proxy.FileName
//forwarded to the RealSubject
proxy.Draw()

fmt.Println(fileName)
Enter fullscreen mode Exit fullscreen mode

Discussion (4)

Collapse
marcello_h profile image
Marcelloh

It is a very helpful list, but what I miss is a bit on the background of a pattern, like in which case the pattern is used for/useful for.

Collapse
soulsbane profile image
Paul Crane

This is great! Haven't had a chance to look through it all in much detail yet but will when I get home. Thanks!

Collapse
tgotwig profile image
Thomas Gotwig

Cool! But... maybe you could make those huge code blocks collapsible? 🙂

like this
content
dev.to/p/editor_guide

Collapse
jacobbishopxy profile image
Jacob Xie

I wish in the future there will be some practical examples by using these patterns. Thanks for sharing!