Decorator Pattern

출처: https://golangbyexample.com/decorator-pattern-golang/

개요

개체를 변경하지 않고 기능을 추가할 수 있음.
=> 이미 테스트가 끝난 코드를 수정하면 안됨 (Open-Closed Principle에 위배됨) 두가지 피자가 존재한다고 가정해보자.

  • vegge mania pizza
  • peppy tofu pizza

UML 다이어그램

decorator pattern UML diagram

코드

pizza.go

package main

type pizza interface {
    getPrice() int
}

peppyPaneer.go

package main

type peppyPaneer struct {
}

func (p *peppyPaneer) getPrice() int {
    return 20
}

veggeMania.go

package main

type veggeMania struct {
}

func (p *veggeMania) getPrice() int {
    return 15
}

토핑을 추가하기 위해 위쪽에 만들어진 구조체들은 더 이상 수정하면 안됨.

cheeseTopping.go

package main

type cheeseTopping struct {
    pizza pizza
}

func (c *cheeseTopping) getPrice() int {
    pizzaPrice := c.pizza.getPrice()
    return pizzaPrice + 10
}

tomatoTopping.go

package main
type tomatoTopping struct {
    pizza pizza
}
func (c *tomatoTopping) getPrice() int {
    pizzaPrice := c.pizza.getPrice()
    return pizzaPrice + 7
}

main.go

package main

import "fmt"

func main() {

    veggiePizza := &veggeMania{}

    //Add cheese topping
    veggiePizzaWithCheese := &cheeseTopping{
        pizza: veggiePizza,
    }

    //Add tomato topping
    veggiePizzaWithCheeseAndTomato := &tomatoTopping{
        pizza: veggiePizzaWithCheese,
    }

    fmt.Printf("Price of veggieMania pizza with tomato and cheese topping is %d\n", veggiePizzaWithCheeseAndTomato.getPrice())

    peppyPaneerPizza := &peppyPaneer{}

    //Add cheese topping
    peppyPaneerPizzaWithCheese := &cheeseTopping{
        pizza: peppyPaneerPizza,
    }

    fmt.Printf("Price of peppyPaneer with tomato and cheese topping is %d\n", peppyPaneerPizzaWithCheese.getPrice())
}

실행 결과

Price of veggieMania pizza with tomato and cheese topping is 32
Price of peppyPaneer with tomato and cheese topping is 30