├── AdapterPattern.go ├── BuilderPattern.go ├── ChainOfResponsibilityPattern.go ├── CommandPattern.go ├── FactoryPattern.go ├── IteratorPattern.go ├── MediatorPattern.go ├── MomentoPattern.go ├── NullObjectPattern.go ├── ObjectPoolPattern.go ├── ObserverPattern.go ├── PrototypePattern.go ├── README.md ├── SingletonPattern.go ├── StatePattern.go └── StrategyPattern.go /AdapterPattern.go: -------------------------------------------------------------------------------- 1 | // Adapter Design Pattern 2 | 3 | // WHAT 4 | // WHY 5 | // HOW 6 | 7 | package main 8 | 9 | import "fmt" 10 | 11 | // Target 12 | type mobile interface { 13 | chargeAppleMobile() 14 | } 15 | 16 | // Concrete Prototype Implementation 17 | type apple struct{} 18 | 19 | func (a *apple) chargeAppleMobile() { 20 | fmt.Println("Charging APPLE mobile") 21 | } 22 | 23 | // Adaptee 24 | type android struct{} 25 | 26 | func (a *android) chargeAndroidMobile() { 27 | fmt.Println("Charging ANDROID mobile") 28 | } 29 | 30 | // Adapter 31 | type androiddapter struct { 32 | android *android 33 | } 34 | 35 | func (ad *androiddapter) chargeAppleMobile() { 36 | ad.android.chargeAndroidMobile() 37 | } 38 | 39 | // Client 40 | type client struct{} 41 | 42 | func (c *client) chargeMobile(mob mobile) { 43 | mob.chargeAppleMobile() 44 | } 45 | 46 | func main() { 47 | // First/Initial Requirement 48 | apple := &apple{} 49 | client := &client{} 50 | client.chargeMobile(apple) 51 | 52 | // Extended requirement i.e. Charge Android Mobile. 53 | android := &android{} 54 | androiddapter := &androiddapter{ 55 | android: android, 56 | } 57 | client.chargeMobile(androiddapter) 58 | } 59 | -------------------------------------------------------------------------------- /BuilderPattern.go: -------------------------------------------------------------------------------- 1 | // Builder Design Pattern 2 | 3 | // What ? 4 | // Why ? 5 | // How ? 6 | // Pros and Cons ? 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | // type houseBuilder struct { 13 | // window string 14 | // door string 15 | // wall string 16 | // floor int 17 | // } 18 | 19 | // func getNewHouseBuilder() houseBuilder { 20 | // return houseBuilder{} 21 | // } 22 | 23 | // func (b *houseBuilder) buildWall() *houseBuilder { 24 | // b.wall = "Wooden Wall" 25 | // return b 26 | // } 27 | 28 | // func (b *houseBuilder) buildWindow() *houseBuilder { 29 | // b.window = "Wooden Window" 30 | // return b 31 | // } 32 | 33 | // func (b *houseBuilder) buildDoor() *houseBuilder { 34 | // b.door = "Wooden Door" 35 | // return b 36 | // } 37 | 38 | // func (b *houseBuilder) buildNumFloor() *houseBuilder { 39 | // b.floor = 2 40 | // return b 41 | // } 42 | 43 | // func main() { 44 | // houseBuilder := getNewHouseBuilder() 45 | // houseBuilder.buildDoor().buildNumFloor().buildWall().buildWindow() 46 | // fmt.Println(houseBuilder) 47 | // } 48 | 49 | //Product 50 | type house struct { 51 | wall string 52 | window string 53 | door string 54 | floor int 55 | } 56 | 57 | // Builder 58 | type houseBuilder struct { 59 | window string 60 | door string 61 | wall string 62 | floor int 63 | } 64 | 65 | func gethouseBuilder() houseBuilder { 66 | return houseBuilder{} 67 | } 68 | 69 | func (b *houseBuilder) buildWall() { 70 | b.wall = "Wooden Wall" 71 | } 72 | 73 | func (b *houseBuilder) buildWindow() { 74 | b.window = "Wooden Window" 75 | } 76 | 77 | func (b *houseBuilder) buildDoor() { 78 | b.door = "Wooden Door" 79 | } 80 | 81 | func (b *houseBuilder) buildNumFloor() { 82 | b.floor = 2 83 | } 84 | 85 | func (b *houseBuilder) buildHouse() house { 86 | return house{ 87 | wall: b.wall, 88 | door: b.door, 89 | window: b.window, 90 | floor: b.floor, 91 | } 92 | } 93 | 94 | // Director 95 | type director struct { 96 | builder houseBuilder 97 | } 98 | 99 | func newDirector(b houseBuilder) *director { 100 | return &director{ 101 | builder: b, 102 | } 103 | } 104 | 105 | func (d *director) buildHouse() house { 106 | d.builder.buildWall() 107 | d.builder.buildDoor() 108 | d.builder.buildWindow() 109 | d.builder.buildNumFloor() 110 | return d.builder.buildHouse() 111 | } 112 | 113 | func main() { 114 | houseBuilder := gethouseBuilder() 115 | 116 | director := newDirector(houseBuilder) 117 | normalHouse := director.buildHouse() 118 | 119 | fmt.Printf("Normal House Wall is : %s\n", normalHouse.wall) 120 | fmt.Printf("Normal House Door is : %s\n", normalHouse.door) 121 | fmt.Printf("Normal House Window is : %s\n", normalHouse.window) 122 | fmt.Printf("Normal House Num Floor is : %d\n", normalHouse.floor) 123 | } 124 | -------------------------------------------------------------------------------- /ChainOfResponsibilityPattern.go: -------------------------------------------------------------------------------- 1 | // Chain of Responsibility Design Pattern 2 | 3 | // WHAT 4 | // WHY 5 | // HOW 6 | 7 | package main 8 | 9 | import "fmt" 10 | 11 | type step interface { 12 | execute() // Func to be executed next. 13 | setNext(step) // Func to set the next func to be executed. 14 | } 15 | 16 | type openFlap struct { 17 | next step 18 | } 19 | 20 | type pressStartButton struct { 21 | next step 22 | } 23 | 24 | type enterPassword struct { 25 | next step 26 | } 27 | 28 | // Open Flap 29 | 30 | func (r *openFlap) execute() { 31 | fmt.Println("Opening Laptop Flap") 32 | r.next.execute() 33 | } 34 | 35 | func (r *openFlap) setNext(next step) { 36 | r.next = next 37 | } 38 | 39 | // Press Button Below 40 | 41 | func (d *pressStartButton) execute() { 42 | fmt.Println("Pressing start button") 43 | d.next.execute() 44 | } 45 | 46 | func (d *pressStartButton) setNext(next step) { 47 | d.next = next 48 | } 49 | 50 | // Enter Password 51 | 52 | func (m *enterPassword) execute() { 53 | fmt.Println("Entering password for Laptop") 54 | fmt.Println("Laptop Opened!") 55 | } 56 | 57 | func (m *enterPassword) setNext(next step) { 58 | m.next = next 59 | } 60 | 61 | func main() { 62 | //Set next for enterPassword step 63 | enterPassword := &enterPassword{} 64 | 65 | //Set next for pressStartButton step 66 | pressStartButton := &pressStartButton{} 67 | pressStartButton.setNext(enterPassword) 68 | 69 | //Set next for openFlap step 70 | openFlap := &openFlap{} 71 | openFlap.setNext(pressStartButton) 72 | 73 | openFlap.execute() 74 | } 75 | -------------------------------------------------------------------------------- /CommandPattern.go: -------------------------------------------------------------------------------- 1 | // Command Design Pattern 2 | 3 | // WHAT 4 | // WHY 5 | // HOW 6 | 7 | package main 8 | 9 | import "fmt" 10 | 11 | //Command interface 12 | type command interface { 13 | execute() 14 | } 15 | 16 | type device interface { // fired on a device 17 | on() 18 | off() 19 | } 20 | 21 | //Concrete class/object implementing command interface 22 | type onCommand struct { // To switch on the device 23 | device device 24 | } 25 | 26 | func (r *onCommand) setDevice(device device) { 27 | r.device = device 28 | } 29 | 30 | func (loc onCommand) execute() { 31 | loc.device.on() 32 | } 33 | 34 | type offCommand struct { // To switch off the device 35 | device device 36 | } 37 | 38 | func (r *offCommand) setDevice(device device) { 39 | r.device = device 40 | } 41 | 42 | func (loc *offCommand) execute() { 43 | loc.device.off() 44 | } 45 | 46 | // Concrete implementation of device interface 47 | // Request Object/Receiver i.e. device where commands will work 48 | type lightBulb struct { 49 | } 50 | 51 | func (lb lightBulb) on() { 52 | fmt.Println("Light bulb ON!") 53 | } 54 | 55 | func (lb lightBulb) off() { 56 | fmt.Println("Light bulb OFF!") 57 | } 58 | 59 | //Invoker 60 | type remote struct { 61 | cmd command 62 | } 63 | 64 | func (r *remote) setCommand(cmd command) { 65 | r.cmd = cmd 66 | } 67 | 68 | func (r *remote) pressButton() { 69 | r.cmd.execute() 70 | } 71 | 72 | func main() { 73 | lightBulb := &lightBulb{} 74 | 75 | onCommand := &onCommand{} 76 | onCommand.setDevice(lightBulb) 77 | 78 | offCommand := &offCommand{} 79 | offCommand.setDevice(lightBulb) 80 | 81 | oncmd := &remote{} 82 | oncmd.setCommand(onCommand) 83 | oncmd.pressButton() 84 | 85 | offcmd := &remote{} 86 | offcmd.setCommand(offCommand) 87 | offcmd.pressButton() 88 | 89 | } 90 | -------------------------------------------------------------------------------- /FactoryPattern.go: -------------------------------------------------------------------------------- 1 | // Factory Design Pattern in Go: 2 | // Why 3 | // What 4 | // How 5 | 6 | package main 7 | 8 | import "fmt" 9 | 10 | // App 11 | type Car interface { 12 | getCar() string 13 | } 14 | 15 | type SedanType struct { 16 | Name string 17 | } 18 | 19 | func getNewSedan() *SedanType { 20 | return &SedanType{} 21 | } 22 | 23 | func (s *SedanType) getCar() string { 24 | return "Honda City" 25 | } 26 | 27 | type HatchBackType struct { 28 | Name string 29 | } 30 | 31 | func getNewHatchBack() *HatchBackType { 32 | return &HatchBackType{} 33 | } 34 | 35 | func (h *HatchBackType) getCar() string { 36 | return "Polo" 37 | } 38 | 39 | func main() { // Client 40 | getCarFactory(1) 41 | getCarFactory(2) 42 | } 43 | 44 | func getCarFactory(cartype int) { // Factory Class/Object 45 | var car Car 46 | if cartype == 1 { 47 | car = getNewHatchBack() 48 | } else { 49 | car = getNewSedan() 50 | } 51 | carInfo := car.getCar() 52 | fmt.Println(carInfo) 53 | } 54 | -------------------------------------------------------------------------------- /IteratorPattern.go: -------------------------------------------------------------------------------- 1 | // Iterator Design Pattern 2 | 3 | // WHAT 4 | // WHY 5 | // HOW 6 | 7 | package main 8 | 9 | import "fmt" 10 | 11 | type User struct { 12 | name string 13 | age int 14 | } 15 | type iterator interface { 16 | hasNext() bool 17 | next() 18 | getCurrentItem() *User 19 | } 20 | 21 | type iterable interface { 22 | getIterator() iterator 23 | } 24 | 25 | // Concrete implementation of iterator interface 26 | type userIterator struct { 27 | index int 28 | users []*User 29 | } 30 | 31 | func (u *userIterator) hasNext() bool { 32 | if u.index < len(u.users) { 33 | return true 34 | } 35 | return false 36 | } 37 | 38 | func (u *userIterator) next() { 39 | if u.hasNext() { 40 | u.index++ 41 | } 42 | } 43 | 44 | func (u *userIterator) getCurrentItem() *User { 45 | if u.hasNext() { 46 | return u.users[u.index] 47 | } 48 | return nil 49 | } 50 | 51 | // Concrete implementation of iterable interface 52 | type userIterableCollection struct { 53 | users []*User 54 | } 55 | 56 | func (u *userIterableCollection) getIterator() iterator { 57 | return &userIterator{ 58 | users: u.users, 59 | } 60 | } 61 | 62 | func main() { 63 | usr1 := &User{ 64 | name: "Mark", 65 | age: 30, 66 | } 67 | 68 | usr2 := &User{ 69 | name: "Anderson", 70 | age: 35, 71 | } 72 | 73 | userIterableCollection := &userIterableCollection{ 74 | users: []*User{usr1, usr2}, 75 | } 76 | 77 | iterator := userIterableCollection.getIterator() 78 | 79 | for iterator.hasNext() { 80 | elm := iterator.getCurrentItem() 81 | fmt.Println("Current Item is ", elm) 82 | iterator.next() 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /MediatorPattern.go: -------------------------------------------------------------------------------- 1 | // Mediator Design Pattern 2 | 3 | // WHAT 4 | // WHY 5 | // HOW 6 | 7 | package main 8 | 9 | import "fmt" 10 | 11 | type flight interface { 12 | requestLanding() 13 | landed() 14 | permitLanding() 15 | } 16 | 17 | type mediator interface { 18 | canLand(flight) bool 19 | notify() 20 | } 21 | 22 | // Concrete implemetation of flight 23 | type BAFlight struct { 24 | mediator mediator 25 | } 26 | 27 | func (f *BAFlight) requestLanding() { 28 | if f.mediator.canLand(f) { 29 | fmt.Println("BAFlight: Is Landing") 30 | } else { 31 | fmt.Println("BAFlight: Is Waiting to be Landed") 32 | } 33 | } 34 | 35 | func (f *BAFlight) landed() { 36 | fmt.Println("BAFlight: Has Landed") 37 | f.mediator.notify() 38 | } 39 | 40 | func (f *BAFlight) permitLanding() { 41 | fmt.Println("BAFlight: Has been permitted Landing") 42 | } 43 | 44 | type JAFlight struct { 45 | mediator mediator 46 | } 47 | 48 | func (f *JAFlight) requestLanding() { 49 | if f.mediator.canLand(f) { 50 | fmt.Println("JAFlight: Is Landing") 51 | } else { 52 | fmt.Println("JAFlight: Is Waiting to be Landed") 53 | } 54 | } 55 | 56 | func (f *JAFlight) landed() { 57 | fmt.Println("JAFlight: Has Landed") 58 | f.mediator.notify() 59 | } 60 | 61 | func (f *JAFlight) permitLanding() { 62 | fmt.Println("JAFlight: Has been permitted Landing") 63 | } 64 | 65 | //Concrete implemnetaiton of the mediator 66 | type flightControlRoom struct { 67 | isRunWayFree bool 68 | flightQueue []flight 69 | } 70 | 71 | func (f *flightControlRoom) canLand(flt flight) bool { 72 | if f.isRunWayFree { 73 | f.isRunWayFree = false 74 | return true 75 | } 76 | f.flightQueue = append(f.flightQueue, flt) 77 | return false 78 | } 79 | 80 | func (f *flightControlRoom) notify() { 81 | if !f.isRunWayFree { 82 | f.isRunWayFree = true 83 | } 84 | if len(f.flightQueue) > 0 { 85 | firstFlight := f.flightQueue[0] 86 | f.flightQueue = f.flightQueue[1:] 87 | firstFlight.permitLanding() 88 | } 89 | } 90 | 91 | func main() { 92 | fControlRoom := &flightControlRoom{ 93 | isRunWayFree: true, 94 | } 95 | baFlight := &BAFlight{ 96 | mediator: fControlRoom, 97 | } 98 | jaFlight := &JAFlight{ 99 | mediator: fControlRoom, 100 | } 101 | 102 | baFlight.requestLanding() 103 | jaFlight.requestLanding() 104 | baFlight.landed() 105 | } 106 | -------------------------------------------------------------------------------- /MomentoPattern.go: -------------------------------------------------------------------------------- 1 | // Momento Design Pattern 2 | 3 | // WHAT 4 | // WHY 5 | // HOW 6 | 7 | package main 8 | 9 | import "fmt" 10 | 11 | type distance struct { 12 | value int 13 | } 14 | 15 | func newDistance() *distance { 16 | return &distance{ 17 | value: 100, 18 | } 19 | } 20 | 21 | func (d *distance) travelled(dis int) { 22 | d.value = d.value - dis 23 | } 24 | 25 | func (d *distance) print() { 26 | fmt.Println("value of Distance is : ", d.value) 27 | } 28 | 29 | // momento implementation 30 | type distanceMomento struct { 31 | distance distance 32 | } 33 | 34 | func (dm *distanceMomento) restore() distance { 35 | return dm.distance 36 | } 37 | 38 | // originator implementation 39 | type distanceOriginator struct { 40 | distance distance 41 | } 42 | 43 | func newDistanceOriginator(distance distance) *distanceOriginator { 44 | return &distanceOriginator{ 45 | distance: distance, 46 | } 47 | } 48 | 49 | func (do *distanceOriginator) saveState() *distanceMomento { 50 | return &distanceMomento{ 51 | distance: do.distance, 52 | } 53 | } 54 | 55 | func (do *distanceOriginator) getState() distance { 56 | return do.distance 57 | } 58 | 59 | func (do *distanceOriginator) setState(distance distance) { 60 | do.distance = distance 61 | } 62 | 63 | func (do *distanceOriginator) restoreFromMomento(dm *distanceMomento) { 64 | do.distance = dm.restore() 65 | } 66 | 67 | // careTeker Implementation 68 | type careTaker struct { 69 | momentos []distanceMomento 70 | } 71 | 72 | func newCareTaker() *careTaker { 73 | return &careTaker{ 74 | momentos: make([]distanceMomento, 0), 75 | } 76 | } 77 | 78 | func (c *careTaker) addMomento(dm distanceMomento) { 79 | c.momentos = append(c.momentos, dm) 80 | } 81 | 82 | func (c *careTaker) getLastIndexMomento() distanceMomento { 83 | lastIndex := len(c.momentos) - 1 84 | lastMomento := c.momentos[lastIndex] 85 | c.momentos = c.momentos[:lastIndex] 86 | return lastMomento 87 | } 88 | 89 | func main() { 90 | dis := newDistance() // 100 91 | careTaker := newCareTaker() 92 | originator := newDistanceOriginator(*dis) 93 | 94 | dis.print() // 100 95 | 96 | // first Momento 97 | m1 := originator.saveState() 98 | careTaker.addMomento(*m1) // 100 99 | 100 | dis2 := originator.getState() 101 | dis2.print() // 100 102 | dis2.travelled(50) 103 | dis2.print() // 50 104 | 105 | // second Momento 106 | originator.setState(dis2) 107 | m2 := originator.saveState() 108 | careTaker.addMomento(*m2) // 50 109 | 110 | dis2.travelled(25) 111 | dis2.print() // 25 112 | 113 | // restoration 114 | lastMomento := careTaker.getLastIndexMomento() 115 | originator.restoreFromMomento(&lastMomento) 116 | dis3 := originator.getState() 117 | dis3.print() // 50 118 | 119 | lastMomento2 := careTaker.getLastIndexMomento() 120 | originator.restoreFromMomento(&lastMomento2) 121 | dis4 := originator.getState() 122 | dis4.print() // 100 123 | } 124 | -------------------------------------------------------------------------------- /NullObjectPattern.go: -------------------------------------------------------------------------------- 1 | // Null Object Design Pattern 2 | 3 | // WHAT 4 | // WHY 5 | // HOW 6 | 7 | package main 8 | 9 | import "fmt" 10 | 11 | // DependenceBase 12 | type studentName interface { 13 | getName() string 14 | } 15 | 16 | //ConcreteDependency 17 | type student struct { 18 | name string 19 | } 20 | 21 | func getNewStudent(name string) *student { 22 | return &student{ 23 | name: name, 24 | } 25 | } 26 | 27 | func (s *student) getName() string { 28 | return s.name 29 | } 30 | 31 | // Null Implementation 32 | type nullStudent struct { 33 | } 34 | 35 | func newNullStudent() *student { 36 | return &student{ 37 | name: "Name of student Not Present", 38 | } 39 | } 40 | 41 | // Factory 42 | type studentFactory struct { 43 | studentNames []string 44 | } 45 | 46 | func getNewStudentFactory() *studentFactory { 47 | return &studentFactory{ 48 | studentNames: []string{"A", "B", "C"}, 49 | } 50 | } 51 | 52 | func (sf *studentFactory) getStudentName(name string) studentName { 53 | studentList := getNewStudentFactory() 54 | 55 | for _, value := range studentList.studentNames { 56 | if name == value { 57 | return getNewStudent(name) 58 | } 59 | } 60 | 61 | return newNullStudent() 62 | } 63 | 64 | // Client 65 | func main() { 66 | students := getNewStudentFactory() 67 | 68 | s1 := students.getStudentName("A") 69 | s2 := students.getStudentName("B") 70 | s3 := students.getStudentName("C") 71 | s4 := students.getStudentName("D") 72 | s5 := students.getStudentName("E") 73 | 74 | fmt.Println("Student Name : ", s1.getName()) 75 | fmt.Println("Student Name : ", s2.getName()) 76 | fmt.Println("Student Name : ", s3.getName()) 77 | fmt.Println("Student Name : ", s4.getName()) 78 | fmt.Println("Student Name : ", s5.getName()) 79 | } 80 | -------------------------------------------------------------------------------- /ObjectPoolPattern.go: -------------------------------------------------------------------------------- 1 | // Object Pool Design Pattern 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "strconv" 8 | ) 9 | 10 | type iDBConnection interface { 11 | getID() string 12 | } 13 | 14 | type connection struct { 15 | id string 16 | } 17 | 18 | func (c *connection) getID() string { 19 | return c.id 20 | } 21 | 22 | type poolConnections struct { 23 | idle []iDBConnection 24 | active []iDBConnection 25 | capacity int 26 | } 27 | 28 | func (p *poolConnections) getConnection() iDBConnection { 29 | if len(p.idle) == 0 { 30 | panic("no connection present in the pool") 31 | } 32 | obj := p.idle[0] 33 | p.idle = p.idle[1:] 34 | p.active = append(p.active, obj) 35 | fmt.Printf("get pool connection with id: %s\n", obj.getID()) 36 | return obj 37 | } 38 | 39 | func (p *poolConnections) returnConnection(target iDBConnection) error { 40 | err := p.remove(target) 41 | if err != nil { 42 | return err 43 | } 44 | p.idle = append(p.idle, target) 45 | fmt.Printf("return pool object with ID: %s\n", target.getID()) 46 | return nil 47 | } 48 | 49 | func (p *poolConnections) remove(target iDBConnection) error { 50 | currentActiveLength := len(p.active) 51 | for i, obj := range p.active { 52 | if obj.getID() == target.getID() { 53 | p.active[currentActiveLength-1], p.active[i] = p.active[i], p.active[currentActiveLength-1] 54 | p.active = p.active[:currentActiveLength-1] 55 | return nil 56 | } 57 | } 58 | return fmt.Errorf("target pool object doesn't belong to the pool") 59 | } 60 | 61 | func initPool(poolObjects []iDBConnection) *poolConnections { 62 | if len(poolObjects) == 0 { 63 | return nil 64 | } 65 | active := make([]iDBConnection, 0) 66 | pool := &poolConnections{ 67 | idle: poolObjects, 68 | active: active, 69 | capacity: len(poolObjects), 70 | } 71 | return pool 72 | } 73 | 74 | func main() { 75 | connections := make([]iDBConnection, 0) 76 | for i := 0; i < 3; i++ { 77 | c := &connection{id: strconv.Itoa(i)} 78 | connections = append(connections, c) 79 | } 80 | pool := initPool(connections) 81 | fmt.Println("Initial connection idle count", len(pool.idle)) 82 | fmt.Println("Initial connection active count", len(pool.active)) 83 | 84 | // Decrease connection counter 85 | conn1 := pool.getConnection() 86 | fmt.Println("connection count after taking first connection out", len(pool.idle)) 87 | conn2 := pool.getConnection() 88 | fmt.Println("connection count after taking second connection out", len(pool.idle)) 89 | conn3 := pool.getConnection() 90 | fmt.Println("connection count after taking third connection out", len(pool.idle)) 91 | 92 | // Increase connection counter 93 | pool.returnConnection(conn1) 94 | fmt.Println("connection count after returning first connection", len(pool.idle)) 95 | pool.returnConnection(conn2) 96 | fmt.Println("connection count after returning second connection", len(pool.idle)) 97 | pool.returnConnection(conn3) 98 | fmt.Println("connection count after returning third connection", len(pool.idle)) 99 | } 100 | -------------------------------------------------------------------------------- /ObserverPattern.go: -------------------------------------------------------------------------------- 1 | // Observer Design Pattern in Go? 2 | // 1. What ? 3 | // 2. Why ? 4 | // 3. How ? 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | ) 11 | 12 | type Publisher interface { 13 | Register(subscriber Subscriber) 14 | NotifyAll(msg string) 15 | } 16 | 17 | type Subscriber interface { 18 | ReactToPublisherMsg(msg string) 19 | } 20 | 21 | // Publisher 22 | type publisher struct { 23 | subscriberList []Subscriber 24 | } 25 | 26 | func GetNewPublisher() publisher { 27 | return publisher{subscriberList: make([]Subscriber, 0)} 28 | } 29 | 30 | func (pub *publisher) Register(subs Subscriber) { 31 | pub.subscriberList = append(pub.subscriberList, subs) 32 | } 33 | 34 | func (pub publisher) NotifyAll(msg string) { 35 | for _, subs := range pub.subscriberList { 36 | fmt.Println("Publisher notifying Subscriber with Id ", subs.(subscriber).subscriberId) // Type Assertion 37 | subs.ReactToPublisherMsg(msg) 38 | } 39 | } 40 | 41 | // Subscriber 42 | type subscriber struct { 43 | subscriberId string 44 | } 45 | 46 | func GetNewSubscriber(Id string) subscriber { 47 | return subscriber{subscriberId: Id} 48 | } 49 | 50 | func (s subscriber) ReactToPublisherMsg(msg string) { 51 | fmt.Println("Subscriber Recieved message", msg, "for subscriber Id ", s.subscriberId) 52 | } 53 | 54 | func main() { 55 | pub := GetNewPublisher() 56 | 57 | subs := GetNewSubscriber("1") 58 | subs1 := GetNewSubscriber("2") 59 | pub.Register(subs) 60 | pub.Register(subs1) 61 | pub.NotifyAll("Hello notifying subscriber") 62 | } 63 | -------------------------------------------------------------------------------- /PrototypePattern.go: -------------------------------------------------------------------------------- 1 | // Prototype Design Pattern in Go? 2 | // 1. What ? 3 | // 2. Why ? 4 | // 3. How ? (Structs, Interfaces and Receiver Functions) 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | ) 11 | 12 | type ShapeType int // Define Custom type here 13 | 14 | const ( 15 | CircleType ShapeType = 1 16 | SquareType ShapeType = 2 17 | ) 18 | 19 | type Shape interface { 20 | GetId() ShapeType // Get the Shape Id 21 | PrintTypeProp() // used for printing proerty values of the Shape 22 | Clone() Shape // used for getting DeepCopy 23 | } 24 | 25 | // Implement Circle 26 | type Circle struct { 27 | Id ShapeType 28 | Radius int 29 | Diameter int 30 | Circumference int 31 | } 32 | 33 | func NewCircle(radius, diameter, circumference int) Circle { 34 | return Circle{CircleType, radius, diameter, circumference} 35 | } 36 | 37 | func (c Circle) GetId() ShapeType { 38 | return c.Id 39 | } 40 | 41 | func (c Circle) Clone() Shape { // Prototyping 42 | return NewCircle(c.Radius, c.Diameter, c.Circumference) 43 | } 44 | 45 | func (c Circle) PrintTypeProp() { 46 | fmt.Println("Circle Properties Radius, Diameter, Circumference:", c.Radius, c.Diameter, c.Circumference) 47 | } 48 | 49 | type Square struct { 50 | Id ShapeType 51 | Length int 52 | Breadth int 53 | } 54 | 55 | func NewSquare(Length, Breadth int) Square { 56 | return Square{SquareType, Length, Breadth} 57 | } 58 | 59 | func (s Square) GetId() ShapeType { 60 | return s.Id 61 | } 62 | 63 | func (s Square) Clone() Shape { 64 | return NewSquare(s.Length, s.Breadth) 65 | } 66 | 67 | func (s Square) PrintTypeProp() { 68 | fmt.Println("Square Properties Length, Breadth: ", s.Length, s.Breadth) 69 | } 70 | 71 | var RegistryList = make(map[int]Shape) // Prototype registry 72 | 73 | func loadToRegistry() { 74 | circle := NewCircle(50, 40, 15) 75 | RegistryList[int(circle.GetId())] = circle // Adding circle to registry 76 | 77 | square := NewSquare(50, 40) 78 | RegistryList[int(square.GetId())] = square // Adding square to registry 79 | } 80 | 81 | func main() { 82 | loadToRegistry() // Load new objects data to Registry 83 | 84 | square := RegistryList[int(SquareType)] 85 | sq, ok := square.(Square) // Type Assertion 86 | if ok { 87 | fmt.Println("Old Properties:") 88 | sq.PrintTypeProp() 89 | newSquare := sq.Clone() // Prototype 90 | fmt.Println("Cloned object Properties:") 91 | newSquare.PrintTypeProp() 92 | } 93 | 94 | circle := RegistryList[int(CircleType)] 95 | cr, ok := circle.(Circle) // Type Assertion 96 | if ok { 97 | fmt.Println("Old Properties:") 98 | cr.PrintTypeProp() 99 | newCircle := cr.Clone().(Circle) // Prototype i.e. Cloning existing object 100 | newCircle.Radius = 35 // Changing property of the prototype without effecting the original object 101 | fmt.Println("Cloned object Changed Properties:") 102 | newCircle.PrintTypeProp() 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoDesignPatterns -------------------------------------------------------------------------------- /SingletonPattern.go: -------------------------------------------------------------------------------- 1 | // Singleton Design Pattern in Go? 2 | // 1. What ? 3 | // 2. Why ? 4 | // 3. How ? 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "sync" 11 | ) 12 | 13 | var mutex = &sync.Mutex{} 14 | 15 | type config struct { 16 | // Config variables 17 | } 18 | 19 | var counter int = 1 20 | var singleConfigInstance *config 21 | 22 | func getConfigInstance() *config { 23 | if singleConfigInstance == nil { 24 | mutex.Lock() 25 | defer mutex.Unlock() 26 | if singleConfigInstance == nil { 27 | fmt.Println("Creting Single Instance Now, and Counter is ", counter) 28 | singleConfigInstance = &config{} 29 | counter = counter + 1 30 | } else { 31 | fmt.Println("Single Instance already created-1, returning that one") 32 | } 33 | } else { 34 | fmt.Println("Single Instance already created-2, returning the same") 35 | } 36 | return singleConfigInstance 37 | } 38 | 39 | func main() { 40 | for i := 0; i < 100; i++ { 41 | go getConfigInstance() 42 | } 43 | fmt.Scanln() 44 | } 45 | -------------------------------------------------------------------------------- /StatePattern.go: -------------------------------------------------------------------------------- 1 | // State Design Pattern 2 | 3 | // WHAT 4 | // WHY 5 | // HOW 6 | 7 | package main 8 | 9 | import "fmt" 10 | 11 | // state 12 | type tvState interface { 13 | state() 14 | } 15 | 16 | //concrete implementation of state 17 | type on struct{} 18 | 19 | func (o *on) state() { // Implementing the Behaviour of ON state 20 | fmt.Println("TV is ON!") 21 | } 22 | 23 | type off struct{} 24 | 25 | func (o *off) state() { // Implementing the Behaviour of OFF state 26 | fmt.Println("TV is OFF!") 27 | } 28 | 29 | // Context 30 | type stateContext struct { 31 | currentTvState tvState 32 | } 33 | 34 | func getContext() *stateContext { 35 | return &stateContext{ 36 | currentTvState: &off{}, 37 | } 38 | } 39 | 40 | func (sc *stateContext) setState(state tvState) { 41 | sc.currentTvState = state 42 | } 43 | 44 | func (sc *stateContext) getState() { 45 | sc.currentTvState.state() 46 | } 47 | 48 | //Client 49 | func main() { 50 | tvContext := getContext() // Default state is OFF 51 | tvContext.getState() // Get the state as OFF 52 | tvContext.setState(&on{}) // Change the current state to ON 53 | tvContext.getState() // Get the state as ON 54 | 55 | } 56 | -------------------------------------------------------------------------------- /StrategyPattern.go: -------------------------------------------------------------------------------- 1 | // Stategy Design Pattern in Go? 2 | // 1. What ? 3 | // 2. Why ? 4 | // 3. How ? (Interfaces, Structs and Receiver Functions) 5 | // 4. Pros and Cons 6 | 7 | package main 8 | 9 | import "fmt" 10 | 11 | type IDBconnection interface { // struct can be assigned any type in runtime 12 | Connect() 13 | } 14 | 15 | type DBConnection struct { 16 | Db IDBconnection // Compatible to accept any type in runtime 17 | } 18 | 19 | func (con DBConnection) DBConnect() { // Receiver Function for struct DBConnection 20 | con.Db.Connect() 21 | } 22 | 23 | // Lets implement First behaviour to connect to MySql 24 | type MySqlConnection struct { 25 | ConnectionString string 26 | } 27 | 28 | func (con MySqlConnection) Connect() { // Receiver Function for struct MySqlConnection 29 | fmt.Println(("MySql " + con.ConnectionString)) 30 | } 31 | 32 | // Second Behaviour 33 | type PostgressConnection struct { 34 | ConnectionString string 35 | } 36 | 37 | func (con PostgressConnection) Connect() { 38 | fmt.Println("Postgress " + con.ConnectionString) 39 | } 40 | 41 | // Third Behaviour 42 | type MongoDbConnection struct { 43 | ConnectionString string 44 | } 45 | 46 | func (con MongoDbConnection) Connect() { 47 | fmt.Println("MongoDb " + con.ConnectionString) 48 | } 49 | 50 | func main() { 51 | 52 | MySqlConnection := MySqlConnection{ConnectionString: "MySql DB is connected"} 53 | con := DBConnection{Db: MySqlConnection} 54 | con.DBConnect() 55 | 56 | pgConnection := PostgressConnection{ConnectionString: "Postgress DB is connected"} 57 | con2 := DBConnection{Db: pgConnection} 58 | con2.DBConnect() 59 | 60 | mgConnection := MongoDbConnection{ConnectionString: "Mongo DB is connected"} 61 | con3 := DBConnection{Db: mgConnection} 62 | con3.DBConnect() 63 | } 64 | --------------------------------------------------------------------------------