Explain design patterns in one sentence

Explain design patterns in one sentence

Most of these patterns have one thing in common, which is to connect producers and consumers through the interface. The abstraction of the interface is the key. It reflects a deep understanding of the underlying type. Knowing this can simply things, no matter what scenario we are dealing with, or what language is being used.

As for why currently there are these patterns, how many there are yet to be discovered, and what mathematical nature is behind them, I can’t answer now.

Creational - How instances are created #

Factory #

The factory method is in charge of creating a series of instances that all implement one common interface. The return type is the interface instead of a concrete class.

 1// type A, B, C all implement I
 2type I interface {}
 3
 4func factory(string t) I {
 5  switch t {
 6    case "A":
 7      return new A()
 8    case "B":
 9      return new B()
10    case "C":
11      return new C()
12  }
13}

Singleton #

One instance throughout the application life-cycle.

 1type A struct{}
 2
 3var (
 4  one *A
 5  m   = &sync.Mutex{}
 6)
 7
 8func Get() {
 9  // prevents unnecessary lock
10  if one == nil {
11    m.Lock()
12    defer m.Unlock()
13
14    // prevents unnecessary creation
15    if one == nil {
16      one = &A{}
17      return one
18    }
19    return one
20  }
21  return one
22}

Prototype #

Instances are obtained by cloning but not instantiating. Their class implements a common interface that defines a clone method, so the return type is an interface but not the concrete class.

 1type I interface {
 2  clone() I
 3}
 4
 5type A struct {}
 6
 7func (a *A) clone() I {
 8  tmp := *a
 9  return &tmp
10}
11
12func main() {
13  var a, a2 I
14  a  = &A{}
15  a2 = a.clone()
16}

Structural - How components collaborate #

Bridge #

Class A delegates tasks to class B. They share a common interface.

 1type I interface {
 2  do() string
 3}
 4
 5type A struct {}
 6func (a A) do() string {
 7  return "hello"
 8}
 9
10type B struct {
11  i I
12}
13func (b B) do() {
14  return b.i.do()
15}
16
17func main() {
18  b:= B{
19    i: A{}
20  }
21  
22  b.do() // => "hello"
23}

Adapter #

Class A interacts with incompatible class B through an adapter.

 1type A interface {
 2  produce() int
 3}
 4
 5type B interface {
 6  consume(string s)
 7}
 8
 9type AtoBAdapter struct {
10  A
11}
12
13func (a AtoBAdapter) produce() string {
14  return strconv.Itoa(a.A.produce())
15}
16
17func main() {
18  a := AtoBAdapter{
19    A: A{}
20  }
21  b := B{}
22
23  b.consume(a.produce())
24}

Composite #

Using a tree-like structure if the business model is recursive.

 1type I interface {
 2  do()
 3}
 4
 5type Component struct {
 6  children []I // can be component or node
 7}
 8
 9func (c Component) do() {
10  for _, child := range r.children {
11    child.do()
12  }
13}
14
15type Node struct {}
16
17func (n Node) do() {}
18
19func main() {
20  c := Component{
21    children: []I{
22      Component{},
23      Node{},
24    }
25  }
26}

Facade #

A new interface is defined for a single-entry-point control. Behind that, it is a complex subsystem that involves many classes.

 1// the only interface for user interaction
 2type I interface {
 3  foo()
 4  bar()
 5}
 6
 7type A interface {
 8  a1()
 9  a2()
10}
11
12type B interface {
13  b1()
14}
15
16type system struct {
17  A
18  B
19}
20func (s system) foo() {
21  s.A.a1()
22  s.B.b1()
23}
24func (s system) bar() {
25  s.A.a2()
26}
27
28func main() {
29  s I := system{
30    A: A{}
31    B: B{} 
32  }
33
34  s.foo()
35  s.bar()
36}

Behavioral - How variation is produced #

Strategy #

The context chooses one of the instances from multiple classes that all implement a common interface.

 1// type A, B, C all implement I
 2type I interface {
 3  do()
 4}
 5
 6func main() {
 7  var executor I
 8
 9  switch strategy {
10    case "A":
11      executor := new A()
12    case "B":
13      executor := new B()
14    case "C":
15      executor := new C()
16  }
17
18  executor.do()
19}

Template #

Class A is a template for classes B C and D to inherit and overwrite to produce variations during definition (not at runtime).

 1type interface I {
 2  foo()
 3  bar()
 4}
 5
 6// a default implementation of I
 7type template struct {}
 8func (t template) foo() {}
 9func (t template) bar() {}
10
11// only overwrites foo
12type A struct {
13  template
14}
15func (a A) foo() {
16  fmt.Print("a foo")
17}
18func (a A) bar() {
19  a.template.bar()
20}
21
22// only overwrites bar
23type B struct {
24  template
25}
26func (b B) foo() {
27  b.template.foo()
28}
29func (b B) bar() {
30  fmt.Print("b bar")
31}

Decorator #

B decorates(wraps) A to mutate the result without changing A’s original behavior.

 1type I interface {
 2  do()
 3}
 4
 5type A struct {}
 6
 7func (a A) do() int {
 8  return 1
 9}
10
11type B struct {
12  i I
13}
14
15func (b B) do() int {
16  return b.i.do() + 1
17}
18
19func main() {
20  a := A{}
21  b := B{
22    i: a
23  }
24
25  a.do() // => 1
26  b.do() // => 2
27}