2022년 10월 8일 토요일

Golang_designpatter_ebook_kth

Golang_designpatter_ebook_kth

Golang Design Pattern 예제

디자인 패턴에 대한 기본 설명은 https://yunhos.blogspot.com/2021/03/kotlindesignpatternebookkth.html 에서 참고.

Creational Patterns

Singleton

//count변수 하나만 가지고 있는 구조체
type singleton struct {  
   count int  
}  
  
var instance *singleton  
  
func GetInstance() *singleton {  
   if instance == nil {  
      instance = new(singleton)  
   }  
   return instance  
}  

// 메소드 리시버로 구조체를 받아서 카운트를 증가하는 초간단로직의 싱글톤  
func (s *singleton) AddOne() int {  
   s.count++  
   return s.count  
}

test

import "testing"  
  
func TestGetInstance(t *testing.T) {  
   counter1 := GetInstance()  
   if counter1 == nil {    
      t.Error("싱글톤 에러")  
   }  
}

Factory

package factory  
  
type iOrderWhat interface {  
   setName(name string)  
   getName() string  
}  
  
type factoryLine struct {  
   name string  
}  
  
func (factoryLine *factoryLine) setName(name string) {  
   factoryLine.name = name  
}  
  
func (factoryLine *factoryLine) getName() string {  
   return factoryLine.name  
}  
  
// 요소의 이름과 타입을 같이 지정하면 bmw.getName() 처럼 함축해서 기술할수 있다  
type BMW struct {  
   factoryLine  
}  
  
func makeBMW() *BMW {  
   return &BMW{  
      factoryLine: factoryLine{  
         name: "BMW",  
      },  
   }  
}  
  
// struct 의 요소에 이름을 지정하면 audi.whichLine.getName() 처럼 호출해야한다.  
type AUDI struct {  
   whichLine factoryLine  
}  
  
  
func makeAUDI() *AUDI {  
   return &AUDI{  
      whichLine: factoryLine{  
         name: "AUDI",  
      },  
   }  
}

test

import "testing"  
  
func TestFactory(t *testing.T) {  
   bmw := makeBMW()  
   if bmw.getName() != "BMW" {  
      t.Error("BMW 제조공장 에러")  
   }  
  
   audi := makeAUDI()  
   if audi.whichLine.getName() != "AUDI" {  
      t.Error("AUDI 제조공장 에러")  
   }  
}

Abstract Factory

package abstractfactory  
  
import "fmt"  

//추상팩토리 인터페이스에서는 각 공장에서 OO를 만들자 라는 공통점을 가지도록한다.
type iAbstractFactory interface {  
   makeProduct() iVechicle  
}  
//탈것 형식에 맞게 생산한다.  
func produceProduct(vechicleType string) (iAbstractFactory, error) {  
   if vechicleType == "car" {  
      return &carFactory{}, nil  
  }  
  
   if vechicleType == "airplane" {  
      return &airplaneFactory{}, nil  
  }  
  
   return nil, fmt.Errorf("그런거 못 만들어요")  
}  

// 자동차 공장  
type carFactory struct {  
}  
// 탈것을 만들되 자동차공장 구조체를 통해서 각부품을 생산한다.   
func (cf *carFactory) makeProduct() iVechicle {  
   return &vechicle{  
      factoring: factoring{  
         engineFactory: engineFactory{ power: "200MP" },  
         wheelFactory:  wheelFactory{count: "4"},  
         wingFactory:   wingFactory{wing: "0"},  
      },  
   }  
}  
  
  
type airplaneFactory struct {  
}  
  
func (cf *airplaneFactory) makeProduct() iVechicle {  
   return &vechicle{  
      factoring: factoring{  
         engineFactory: engineFactory{ power: "3200MP" },  
         wheelFactory:  wheelFactory{count: "3"},  
         wingFactory:   wingFactory{wing: "2"},  
      },  
   }  
}  
  
// 탈것이 공통으로 가질 속성을 정의한다.  
type iVechicle interface {  
  setPower(power string)  
   getPower() string  
  setWheel(wheel string)  
   getWheel() string  
  setWing(wing string)  
   getWing() string  
}  

// 생산과정에서 엔진, 바퀴, 날개 각 공장을 통해 생산한다. 
type factoring struct {  
   engineFactory  
   wheelFactory 
   wingFactory
}  

// 탈것은 생산을 통해 만들어 진다.  
type vechicle struct {  
   factoring  
}  

// 탈것의 공통속성에 대한 구현을 한다.  
func (v vechicle) getPower() string {  
   return v.power  
}  
func (v vechicle) getWheel() string {  
   return v.count  
}  
func (v vechicle) getWing() string {  
   return v.wing  
}  
func (v vechicle) setPower(power string) {  
   v.power = power  
}  
func (v vechicle) setWheel(wheel string) {  
   v.count = wheel  
}  
func (v vechicle) setWing(wing string) {  
   v.wing = wing  
}  
  
//각 공장을 정의한다.  
type engineFactory struct {  
   power string  
}  
type wheelFactory struct {  
   count string  
}  
type wingFactory struct {  
   wing string  
}  

test

package abstractfactory  
  
import (  
   "testing"  
)  
  
func TestFactory(t *testing.T) {  
   produce, _ := produceProduct("car")  
   myCar := produce.makeProduct()  
   if myCar.getPower() != "200MP" {  
      t.Error("자동차  마력은 200MP")  
   }  
  
   produce2, _ := produceProduct("airplane")  
   myAirplain := produce2.makeProduct()  
   if myAirplain.getPower() != "3200MP" {  
      t.Error("비행기 마력은 3200MP")  
   }  
  
}

Builder Factory

package builder  
  
type iCoffeResources interface {  
   setCoffee(coffee int) iCoffeResources  
  setSugar(suger int) iCoffeResources  
  setCream(cream int) iCoffeResources  
  getResources() *coffeResource  
}  
  
type coffeResource struct {  
   coffe int  
  sugar int  
  cream int  
}  
  
func (coffeMix *coffeResource) getResources()  *coffeResource {  
   return coffeMix;  
}  
  
func (coffeMixer *coffeResource) setCoffee(coffee int) iCoffeResources {  
   coffeMixer.coffe = coffee  
  return coffeMixer  
}  
func (coffeMixer *coffeResource) setSugar(sugar int) iCoffeResources {  
   coffeMixer.sugar = sugar  
  return coffeMixer  
}  
func (coffeMixer *coffeResource) setCream(cream int) iCoffeResources {  
   coffeMixer.cream = cream  
  return coffeMixer  
}  
  
// 기본 재료 세팅  
func newCoffeBulder() iCoffeResources {  
   return &coffeResource{  
      coffe: 0,  
      sugar: 0,  
      cream: 0,  
   }  
}  
  
// 재료로 커피 생산 func produceCoffee(r iCoffeResources) coffeResource {  
   return coffeResource{  
      coffe: r.getResources().coffe,  
      sugar: r.getResources().sugar,  
      cream: r.getResources().cream,  
   }  
}  
  
  
func coffeMachine(coffeType string) coffeResource {  
  
   baseCoffee := newCoffeBulder()  
   if coffeType == "espresso" {  
      baseCoffee.setCoffee(2)  
   }  
   if coffeType == "mix" {  
      baseCoffee.setCoffee(1).setCream(1).setSugar(1)  
   }  
   return produceCoffee(baseCoffee)  
}

test

package builder  
  
import (  
   "testing"  
)  
  
func TestFactory(t *testing.T) {  
   coffeeMachine := coffeMachine("espresso")  
   if coffeeMachine.coffe != 2 {  
      t.Error("에소프레소는 커피2")  
   }  
  
   coffeeMachine = coffeMachine("mix")  
   if coffeeMachine.cream != 1 || coffeeMachine.sugar != 1 || coffeeMachine.coffe != 1{  
      t.Error("믹스 커피의 조합은 1:1:1")  
   }  
  
}

Structural Patterns

Decorator Pattern

package decorator  
  
type iHambugger interface {  
   getPrice() int  
}  
type hambugger struct {  
   price int  
}  
func (h *hambugger) getPrice() int {  
   return 1000  
}  
  
type meetTopping struct {  
   iHambugger  
}  
  
func (m *meetTopping) getPrice() int {  
   return m.iHambugger.getPrice() + 300  
}  
  
type eggTopping struct {  
   iHambugger  
}  
  
func (e *eggTopping) getPrice() int {  
   return e.iHambugger.getPrice() + 200  
}

test

package decorator  
  
import (  
   "testing"  
)  
  
func TestFactory(t *testing.T) {  
   baseBugger := &hambugger{}  
  
   meetOnlyBugger := &meetTopping{  
      iHambugger: baseBugger,  
   }  
  
   if meetOnlyBugger.getPrice() != 1300 {  
      t.Error("미트버거 계산오류")  
   }  
  
   eggOnlyBugger := &eggTopping{  
      iHambugger: baseBugger,  
   }  
  
   if eggOnlyBugger.getPrice() != 1200 {  
      t.Error("에그버거 계산오류")  
   }  
  
  
   meetEggBugger := &eggTopping{  
      iHambugger: meetOnlyBugger,  
   }  
  
   if meetEggBugger.getPrice() != 1500 {  
      t.Error("미트에그버거 계산오류")  
   }  
  
  
}

Adaptor Pattern

package adaptor  
  
type toTypeC interface {  
   connect() string  
}  
  
type usb1 struct {  
}  
  
func (u *usb1) connect() string {  
   return "usb1 연결"  
}  
  
type thunderbird struct {  
}  
  
func (u *thunderbird) connect() string {  
   return "썬더보드 연결"  
}  
  
type computer struct {  
  
}  
  
func (c *computer) connectCable(typeC toTypeC) string {  
   return typeC.connect()  
}

test

package adaptor  
  
import (  
   "testing"  
)  
  
func TestFactory(t *testing.T) {  
   computer := &computer{}  
   msg := computer.connectCable(&usb1{})  
  
   if msg != "usb1 연결" {  
      t.Error("usb1 연결오류")  
   }  
  
   msg = computer.connectCable(&thunderbird{})  
   if msg != "썬더보드 연결" {  
      t.Error("썬더보드 연결오류")  
   }  
}

Bridge Pattern

package bridge  
  
type mac struct {  
   printer  
}  
  
func (m *mac) print() string {  
   return m.printer.printFile()  
}  
  
func (m *mac) setPrinter(p printer) {  
   m.printer = p  
}  
  
type printer interface {  
   printFile() string  
}  
  
type epson struct {}  
  
func (e *epson) printFile()  string {  
   return "epson"  
}  
  
type samsung struct {}  
  
func (e *samsung) printFile()  string {  
   return "samsung"  
}

test

package bridge  
  
import "testing"  
  
func TestFactory(t *testing.T) {  
   mac := &mac{}  
  
   epson := &epson{}  
   mac.setPrinter(epson)  
  
   if mac.print() != "epson" {  
      t.Error("epson 프린터 오류")  
   }  
   samsung := &samsung{}  
   mac.setPrinter(samsung)  
  
   if mac.print() != "samsung" {  
      t.Error("samsung 프린터 오류")  
   }  
  
}

Composite Pattern

package composite  
  
import "fmt"  
  
type fileFolderComponent interface {  
   display()  
}  
  
type file struct {  
   name string  
}  
  
func (f *file) display()  {  
   fmt.Println(f.name)  
}  
  
type folder struct {  
   components []fileFolderComponent  
  name string  
}  
  
func (f *folder) display()   {  
   fmt.Println(f.name)  
   for _, composite := range f.components {  
      composite.display()  
   }  
}  
  
func (f *folder) add(c fileFolderComponent)  {  
   f.components = append(f.components, c)  
}

test

package composite  
  
import "testing"  
  
func TestFactory(t *testing.T) {  
   file1 := &file{name: "file1"}  
   file2 := &file{name: "file2"}  
   file3 := &file{name: "file3"}  
  
   folder1 := &folder{  
      name: "/",  
   }  
   folder1.add(file1)  
  
   folder2 := &folder{  
      name: "/sub",  
   }  
   folder2.add(file2)  
   folder2.add(file3)  
  
   folder1.add(folder2)  
  
   folder1.display()  
  
}

Flyweight Pattern

package flyweight  
  
import "fmt"  
  
type enermy struct {  
   name string  
  cached bool  
}  
type iEnermy interface {  
   getName() string  
  attack()  
   setCached(cache bool)  
   getCached() bool  
}  
  
func (e *enermy) getName() string{  
   return e.name  
}  
  
func (e *enermy) attack() {  
   fmt.Print("attack")  
}  
  
func (e *enermy) setCached(cache bool) {  
   e.cached = cache  
}  
  
func (e *enermy) getCached()  bool{  
   return e.cached  
}  
  
type enermyFactory struct {  
   enermies map[string]iEnermy  
}  
  
func (ef *enermyFactory) getEnermy(ename string) (iEnermy, error)  {  
   if ef.enermies[ename] != nil {  
      ef.enermies[ename].setCached(true)  
      return ef.enermies[ename], nil  
  }  
   ef.enermies[ename] = &enermy{  
      name:   ename,  
      cached: false,  
   }  
   return ef.enermies[ename], nil  
}

test

package flyweight  
  
import "testing"  
  
func TestFactory(t *testing.T) {  
   enermyFactory := &enermyFactory{  
      enermies: map[string]iEnermy{},  
   }  
  
   enermy1, _ := enermyFactory.getEnermy("goblin")  
  
   if enermy1.getName() != "goblin" {  
      t.Error("goblin이 아님")  
   }  
  
   enermy2 , _ := enermyFactory.getEnermy("devil")  
   if enermy2.getName() != "devil" {  
      t.Error("devil 아님")  
   }  
  
   enermy3, _ := enermyFactory.getEnermy("goblin")  
   if enermy3.getCached() != true {  
      t.Error("goblin이 캐쉬되지 않음")  
   }  
  
}

Facade Pattern

package facade  
  
type facade struct {  
   toResult iVeryComplexLogic  
}  
  
type iVeryComplexLogic interface {  
   idontknow() string  
}  
  
func (f *facade) idontknow() string {  
   return "idontknow"  
}

test

import "testing"  
  
func TestFactory(t *testing.T) {  
   facade := facade{}  
   if facade.idontknow() != "idontknow" {  
      t.Error("idontknow 아님")  
   }  
}

Proxy Pattern

package proxy  
  
type iProxyService interface {  
   connectSite() string  
}  
  
type proxyService struct {  
     
}  
  
func (p *proxyService) connectSite() string {  
   return "connected"  
}  
  
type proxyPattern struct {  
   proxy iProxyService  
}  
  
func (p *proxyPattern) run() string {  
   return p.proxy.connectSite()  
}

test

package proxy  
  
import (  
   "testing"  
)  
  
func TestFactory(t *testing.T) {  
   proxyPattern := proxyPattern{  
      proxy: &proxyService{},  
   }  
   if proxyPattern.run() != "connected" {  
      t.Error("proxy 연결안됨")  
   }  
}

Behavior Patterns

Strategy Pattern

package behavior  
 
type iDiscount interface {  
  discount() int  
}  
 
type ruleChild struct {  
    
}  
 
func (c *ruleChild) discount() int {  
  return -1000  
}  
 
type ruleAdult struct {  
 
}  
 
func (c *ruleAdult) discount() int {  
  return 0  
}  
 
type busChager struct {  
  basePrice int  
}  
 
func (b *busChager) getPrice(d iDiscount) int {  
  return b.basePrice - d.discount()  
}

test

package behavior  
  
import "testing"  
  
  
func TestFactory(t *testing.T) {  
   busChager := busChager{  
      basePrice: 1500,  
   }  
   child := &ruleChild{}  
  
   if busChager.getPrice(child) != 500 {  
      t.Error("아동 할인 오류")  
   }  
   adult := &ruleAdult{}  
  
   if busChager.getPrice(adult) != 1500 {  
      t.Error("어른은 얄짤 없음")  
   }  
}

Strategy Pattern

package state  
  
type states interface {  
   getStateTest() string  
  nextSteate() states  
}  
  
type born struct {}  
func (b *born) getStateTest() string {  
   return "태어남"  
}  
func (b *born) nextSteate() states {  
   return &infant{}  
}  
  
type infant struct {}  
func (b *infant) getStateTest() string {  
   return "아기때"  
}  
func (b *infant) nextSteate() states {  
   return &adult{}  
}  
  
type adult struct {}  
func (b *adult) getStateTest() string {  
   return "어른"  
}  
func (b *adult) nextSteate() states {  
   return &die{}  
}  
  
type die struct {}  
func (b *die) getStateTest() string {  
   return "죽어서 환생준비"  
}  
func (b *die) nextSteate() states {  
   return &born{}  
}  
  
type lifeIs struct {  
   state states  
}  
  
func (life *lifeIs) nextStep()  {  
   life.state = life.state.nextSteate()  
}

test

  
import (  
   "testing"  
)  
  
  
func TestFactory(t *testing.T) {  
   mylife := &lifeIs{ state: &born{}}  
  
   if mylife.state.getStateTest() != "태어남" {  
      t.Error("아직 안태어남")  
   }  
  
   mylife.nextStep()  
   mylife.nextStep()  
  
   if mylife.state.getStateTest() != "어른" {  
      t.Error("아직 어른이?")  
   }  
}

Command Pattern

package command  
  
type parts interface {  
   on()  
   off()  
}  
  
type printer struct {  
   status string  
}  
  
func (p *printer) on()  {  
   p.status = "on"  
}  
  
func (p *printer) off()  {  
   p.status = "off"  
}  
  
  
type commander interface {  
   execute(p parts)  
}  
type turnonCommand struct {  
  
}  
  
func (t *turnonCommand) execute(p parts)  {  
   p.on()  
}  
  
type remoteControler struct {  
   commander  
}  
  
func (r *remoteControler) powerOn(p parts)  {  
   r.commander.execute(p)  
}

test

package command  
  
  
import "testing"  
  
  
func TestFactory(t *testing.T) {  
   remoteController := &remoteControler{  
      commander: &turnonCommand{},  
   }  
   printer := &printer{ status: "off"}  
   remoteController.powerOn(printer)  
   if printer.status != "on" {  
      t.Error("on")  
   }  
}

Chain Of Responsibility Pattern

package chainofresponsibility  
  
type process interface {  
   canBill(amount int) bool  
  runBill(amount int)  
   next() bankinfo  
}  
  
type bankinfo interface {  
   process  
  setNextBank(nb bankinfo)  
}  
  
type bank1 struct {  
   remain int  
  nextBank bankinfo  
}  
func (b *bank1) next() bankinfo {  
   return b.nextBank  
}  
  
func (b *bank1) setNextBank(nb bankinfo)  {  
   b.nextBank = nb  
}  
  
func (b *bank1) canBill(amount int) bool {  
   return b.remain - amount > 0  
}  
  
func (b *bank1) runBill(amount int)  {  
   b.remain = b.remain - amount  
}  
type bank2 struct {  
   remain int  
  nextBank bankinfo  
}  
func (b *bank2) next() bankinfo {  
   return b.nextBank  
}  
  
  
func (b *bank2) setNextBank(nb bankinfo)  {  
   b.nextBank = nb  
}  
  
func (b *bank2) canBill(amount int) bool {  
   return b.remain - amount > 0  
}  
  
func (b *bank2) runBill(amount int)  {  
   b.remain = b.remain - amount  
}  
type bank3 struct {  
   remain int  
  nextBank bankinfo  
}  
func (b *bank3) next() bankinfo {  
   return b.nextBank  
}  
  
  
func (b *bank3) setNextBank(nb bankinfo)  {  
   b.nextBank = nb  
}  
  
func (b *bank3) canBill(amount int) bool {  
   return b.remain - amount > 0  
}  
  
func (b *bank3) runBill(amount int)  {  
   b.remain = b.remain - amount  
}  
  
type chainOfBank struct {  
   bankinfo  
}  
  
func (c *chainOfBank) next()  {  
   c.bankinfo = c.bankinfo.next()  
}

test

package chainofresponsibility  
  
import "testing"  
  
func TestFactory(t *testing.T) {  
   bank3 := &bank3{  
      remain: 1000,  
      nextBank:  nil,  
   }  
   bank2 := &bank2{  
      remain: 5000,  
      nextBank:  bank3,  
   }  
  
   bank1 := &bank1{  
      remain: 1000,  
      nextBank:  bank2,  
   }  
   wantMoney := 3000  
  remoteController := &chainOfBank{  
      bankinfo: bank1,  
   }  
   if remoteController.bankinfo.canBill(wantMoney) {  
      t.Error("에헤헤..은행1 미쳤냐?")  
   }  
   remoteController.next()  
  
   if !remoteController.bankinfo.canBill(wantMoney) {  
      t.Error("에헤헤..은행2 미쳤냐?")  
   }  
}

Mediator Pattern

https://golangbyexample.com/mediator-design-pattern-golang/ 참고하였음. kotlin의 비행관제센터와 같은 맥락임.

package Mediator  
  
import "fmt"  
  
type train interface {  
   arrive()  
   depart()  
   permitArrival()  
}  
  
type passengerTrain struct {  
   mediator mediator  
}  
  
func (g *passengerTrain) arrive() {  
   if !g.mediator.canArrive(g) {  
      fmt.Println("PassengerTrain: Arrival blocked, waiting")  
      return  
  }  
   fmt.Println("PassengerTrain: Arrived")  
}  
  
func (g *passengerTrain) depart() {  
   fmt.Println("PassengerTrain: Leaving")  
   g.mediator.notifyAboutDeparture()  
}  
  
func (g *passengerTrain) permitArrival() {  
   fmt.Println("PassengerTrain: Arrival permitted, arriving")  
   g.arrive()  
}  
type freightTrain struct {  
   mediator mediator  
}  
  
func (g *freightTrain) arrive() {  
   if !g.mediator.canArrive(g) {  
      fmt.Println("FreightTrain: Arrival blocked, waiting")  
      return  
  }  
   fmt.Println("FreightTrain: Arrived")  
}  
  
func (g *freightTrain) depart() {  
   fmt.Println("FreightTrain: Leaving")  
   g.mediator.notifyAboutDeparture()  
}  
  
func (g *freightTrain) permitArrival() {  
   fmt.Println("FreightTrain: Arrival permitted")  
   g.arrive()  
}  
  
  
type mediator interface {  
   canArrive(train) bool  
  notifyAboutDeparture()  
}  
  
type stationManager struct {  
   isPlatformFree bool  
  trainQueue []train  
}  
  
func newStationManger() *stationManager {  
   return &stationManager{  
      isPlatformFree: true,  
   }  
}  
  
func (s *stationManager) canArrive(t train) bool {  
   if s.isPlatformFree {  
      s.isPlatformFree = false  
  return true  
  }  
   s.trainQueue = append(s.trainQueue, t)  
   return false  
}  
  
func (s *stationManager) notifyAboutDeparture() {  
   if !s.isPlatformFree {  
      s.isPlatformFree = true  
  }  
   if len(s.trainQueue) > 0 {  
      firstTrainInQueue := s.trainQueue[0]  
      s.trainQueue = s.trainQueue[1:]  
      firstTrainInQueue.permitArrival()  
   }  
}

test

package Mediator  
  
  
import (  
"testing"  
)  
  
  
func TestFactory(t *testing.T) {  
  
   stationManager := newStationManger()  
  
   passengerTrain := &passengerTrain{  
      mediator: stationManager,  
   }  
   freightTrain := &freightTrain{  
      mediator: stationManager,  
   }  
  
   passengerTrain.arrive()  
   freightTrain.arrive()  
   passengerTrain.depart()  
}

Mediator Pattern

package memento  
  
// 기념비에 대한 설명을 보존  
type originator struct {  
   state string  
}  
  
func (e *originator) createMemento() *memento {  
   return &memento{state: e.state}  
}  
  
func (e *originator) restoreMemento(m *memento) {  
   e.state = m.getSavedState()  
}  
  
func (e *originator) setState(state string) {  
   e.state = state  
}  
  
func (e *originator) getState() string {  
   return e.state  
}  
  
//순수객체  
type memento struct {  
   state string  
}  
  
func (m *memento) getSavedState() string {  
   return m.state  
}  
  
// 기념비목록을 추가,관리  
type caretaker struct {  
   mementoArray []*memento  
}  
  
func (c *caretaker) addMemento(m *memento) {  
   c.mementoArray = append(c.mementoArray, m)  
}  
  
func (c *caretaker) getMemento(index int) *memento {  
   return c.mementoArray[index]  
}

test

type originator struct {  
   state string  
}  
  
func (e *originator) createMemento() *memento {  
   return &memento{state: e.state}  
}  
  
func (e *originator) restoreMemento(m *memento) {  
   e.state = m.getSavedState()  
}  
  
func (e *originator) setState(state string) {  
   e.state = state  
}  
  
func (e *originator) getState() string {  
   return e.state  
}  
  
//순수객체  
type memento struct {  
   state string  
}  
  
func (m *memento) getSavedState() string {  
   return m.state  
}  
  
// 기념비목록을 추가,관리  
type caretaker struct {  
   mementoArray []*memento  
}  
  
func (c *caretaker) addMemento(m *memento) {  
   c.mementoArray = append(c.mementoArray, m)  
}  
  
func (c *caretaker) getMemento(index int) *memento {  
   return c.mementoArray[index]  
}

Visitor Pattern

package visitor  
  
import "fmt"  
  
type camera interface {  
   display()  
   cleanCheck()  
   visit() bool  
}  
  
type Room1 struct {  
   visior iVisitor  
}  
  
func (r *Room1) display() {  
   fmt.Print("1번방 카메라보기")  
}  
  
func (r *Room1) cleanCheck() {  
   fmt.Print("1번방 청소확인")  
}  
  
func (r *Room1) visit() bool{  
   r.visior.visitForRoom1(r)  
   return true  
}  
type Room2 struct {  
   visior iVisitor  
}  
  
func (r *Room2) display() {  
   fmt.Println("1번방 카메라보기")  
}  
  
func (r *Room2) cleanCheck() {  
   fmt.Println("1번방 청소확인")  
}  
  
func (r *Room2) visit() bool{  
   r.visior.visitForRoom2(r)  
   return true;  
}  
  
type iVisitor interface {  
   visitForRoom1(room1 *Room1)  
   visitForRoom2(room2 *Room2)  
}  
  
type visitor struct {  
   visitorName string  
}  
  
func (v *visitor) visitForRoom1(room1 *Room1) {  
   fmt.Println(v.visitorName)  
   room1.display()  
   room1.cleanCheck()  
}  
  
func (v *visitor) visitForRoom2(room2 *Room2) {  
   fmt.Println(v.visitorName)  
   room2.display()  
   room2.cleanCheck()  
}

test

package visitor  
  
import (  
"testing"  
)  
  
  
func TestFactory(t *testing.T) {  
  
   visitor1 := visitor{visitorName: "책임운영자"}  
  
   room1 := Room1{  
      visior: &visitor1,  
   }  
  
   if !room1.visit() {  
      t.Error("책임운영자 1번방 확인실패")  
   }  
  
   visitor2 := visitor{visitorName: "감시자"}  
   room1 = Room1{  
      visior: &visitor2,  
   }  
  
   if !room1.visit() {  
      t.Error("감시자 1번방 확인실패")  
   }  
  
}

Template Pattern

package template  
  
import "fmt"  
  
type dailyRoutine interface {  
   commute()  
   toWork  
  eatLunch()  
   goHome()  
   showTeamsDailyroutine()  
}  
type toWork interface {  
   toWork()  
}  
  
type commonRoutine struct {  
   toWork  
}  
  
func (c *commonRoutine) commute() {  
   fmt.Println("commute")  
}  
  
func (c *commonRoutine) eatLunch() {  
   fmt.Println("eatLunch")  
}  
  
func (c *commonRoutine) goHome() {  
   fmt.Println("gohome")  
}  
  
func (c *commonRoutine) showTeamsDailyroutine() {  
   c.commute()  
   c.toWork.toWork()  
   c.eatLunch()  
   c.goHome()  
}  
  
type hrTeam struct {  
  
}  
  
func (h *hrTeam) toWork() {  
   fmt.Println("work is seek!seek!seek!")  
}  
  
type devTeam struct {  
  
}  
  
func (h *devTeam) toWork() {  
   fmt.Println("work is coding!coding!coding!")  
}

test

package template  
  
import "testing"  
  
  
func TestFactory(t *testing.T) {  
   hrTeamWork := hrTeam{}  
  
   baseRoutine := commonRoutine{  
      toWork: &hrTeamWork,  
   }  
   baseRoutine.showTeamsDailyroutine()  
  
   baseRoutine = commonRoutine{  
      toWork: &devTeam{},  
   }  
   baseRoutine.showTeamsDailyroutine()  
  
}

Observer Pattern

package Observer  
  
import (  
   "container/list"  
 "fmt")  
  
type subscriber struct {  
   name string  
}  
  
func (s *subscriber) onUpdate(msg string) {  
   fmt.Println("구독자:", s.name, "메시지:", msg)  
}  
  
type iPublisher interface {  
   update(text string)  
   add(subscriber)  
   delete(subscriber)  
}  
  
type newsPublisher struct {  
   subscribers *list.List  
}  
  
func (n *newsPublisher) update(text string) {  
   for e := n.subscribers.Front(); e != nil; e = e.Next() {  
      s := e.Value.(subscriber)  
      s.onUpdate(text)  
   }  
}  
  
func (n *newsPublisher) add(s subscriber) {  
   n.subscribers.PushBack(s)  
}  
  
func (n *newsPublisher) delete(s subscriber) {  
   var removeItem subscriber  
  for e := n.subscribers.Front(); e != nil; e = e.Next() {  
      removeItem =  e.Value.(subscriber)  
      if s == removeItem {  
         n.subscribers.Remove(e)  
         break;  
      }  
   }  
}

test

package Observer  
  
import (  
   "container/list"  
 "testing")  
  
  
func TestFactory(t *testing.T) {  
   newsCenter := newsPublisher{  
      subscribers: new(list.List),  
   }  
   subscriber1 := subscriber{name: "sub1"}  
   subscriber2 := subscriber{name: "sub2"}  
   subscriber3 := subscriber{name: "sub3"}  
  
   newsCenter.add(subscriber1)  
   newsCenter.add(subscriber2)  
   newsCenter.add(subscriber3)  
  
   newsCenter.update("new~~~s")  
  
   newsCenter.delete(subscriber2)    
   newsCenter.update("1,3 new~~~s")  
}

0 comments:

댓글 쓰기