구조패턴 이란?

구조패턴 은 구조를 유연하고 효율적으로 유지하면서 객체들과 클래스들을 더 큰 구조로 조립하는 방법을 설명한다.

 

그중 데코레이터 패턴에 대해 학습해보고자 한다.

데코레이터 패턴 이란?

데코레이터 패턴 이란 주어진 상황 및 용도에 따라 어떤 객체에 책임을 덧붙이는 패턴으로, 기능 확장이 필요할 때 서브클래싱 대신 쓸 수 있는 유연한 대안이 될 수 있다. - 위키

데코레이터는 객체들을 새로운 행동들을 포함한 특수 래퍼 객체들 내에 넣어서 위 행동들을 해당 객체들에 연결시키는 구조적 디자인 패턴이다.

데코레이터 패턴으로 객체에 추가 요소를 동적으로 더할 수 있으며, 데코레이터를 사용하면 서브클래스를 만들 때 보다 유연하게 기능을 확장할 수 있다.

데코레이터 말 그대로 장식에 대해 생각하면 된다. 

 

왜 사용하는가?

코드의 유연성, 확장성, 재사용성을 높이고 객체 지향 설계원칙을 준수하기 위해 사용된다.

 

객체의 동적인 기능 확정과 코드의 재사용성, 유연성을 동시에 제공하기 위해 사용된다.

객체지향 설계원칙을 따르고 있으며, 객체 간의 결합도를 낮추고 코드의 유지보수성을 향상한다.

 

구조

 

구루 에서 제공되는 구조,

 

컴포넌트 즉 구현되어야 할 매개체를 인터페이스로 명시하고, 해당 인터페이스를 구현하는 객체 그리고 데코레이터는 인터페이스와 동일한  함수를 구현하게 해 인터페이스 호출이 가능하도록 작성한다.

이렇게 작성된 구조체에 함수들은 주입받은 객체를 호출하고 본인을 호출하면 마치 체이닝 걸린 것처럼 연속적으로 호출되게 된다.

코드로 보면 보다 이해하기 쉽다.

type beverage interface {
	cost() float32
	getDescription() string
}

type HouseBlend struct {
	description string
}

func (h *HouseBlend) cost() float32 {
	return 0.89
}
func (h *HouseBlend) getDescription() string {
	return h.description
}

type DarkRost struct {
	description string
}

func (d *DarkRost) cost() float32 {
	return 1.32
}
func (d *DarkRost) getDescription() string {
	return d.description
}

type Milk struct {
	b beverage
}

func (m *Milk) cost() float32 {
	return m.b.cost() + 12.3
}
func (m *Milk) getDescription() string {
	return m.b.getDescription() + " milk"
}

type Whip struct {
	b beverage
}

func (w *Whip) cost() float32 {
	return w.b.cost() + 15.5
}
func (w *Whip) getDescription() string {
	return w.b.getDescription() + " whip"
}

func StartHead() {
	//case 1
	a := &HouseBlend{"house coffee"}
	b := &Milk{a}
	c := &Whip{b}

	fmt.Println(c.cost(), c.getDescription())
	//case2
	var B beverage
	B = &HouseBlend{"house"}
	B = &Milk{B}
	B = &Whip{B}

	fmt.Println(B.cost())
}

음료 인터페이스가 있고, 기존 구현체인 HouseBlend, DarkLost 가 존재하고 있으며 데코레이터로 우유와 휘핑 이 있다. 이렇게 되면 데코레이터의 구현체는 주입받은 인터페이스를 이용해 호출하고 데코레이터에서 하고 싶은 함수를 호출하면 된다. 이렇게 기존함수를 호출 함에 따라 마치 연쇄적으로 함수가 동작하는듯한 효과를 가져온다.

 

실행의 결괏값은 아래와 같다.

- 28.69 house coffee milk whip

하우스블랜드 0.89 => 우유 12.3 => 휘핑 15.5 가 차례대로 호출되며 28.69 가 나오게 된다.

순차적으로 실행되는 듯한 느낌이 마치 장식을 해주는 것과 같은 것이 데코레이터패턴 의 이름은 정말 잘 지은 것 같다.

저위에 작성된 클라이언트 코드에서는 case1과 case2로 나누어서 사용한다. 보면 1번의 경우 하나씩 스택을 쌓아가는 반면 

2번 케이스는 인터페이스하나로 받아가면서 사용한다. 

이렇게 됐을 때 2번의 경우로 작성한다면 다형성을 적용하여 보다 폭넓게 사용가능하다. 

 

고 언어에서 활용되는 기본 패키지 둘 중에 데코레이터 패턴이 적용된 것을 살펴보면

compress 패키지 에는 gzip, flate, zip 등의 패키지에서 io.Reader io.Writer 인터페이스를 구현해 데이터 압축 기능을 추가하는

데코레이터 역할을 한다.

 

+ Recent posts