우선 행동패턴 이 무엇이기에 하나의 큰 카테고리 가 되었는지 부터 알아보자
행동패턴 이란 ?(Behavioral Patterns)
소프트웨어 엔지니어링에서 행동 디자인 패턴은 개체 간의 일반적인 통신 패턴을 식별하는 디자인 패턴.
알고리즘 및 개체 간의 책임 할당 과 관련이 있다.
목적
객체 간의 상호작용과 책임 분배를 구조화하고, 객체의 행동을 유연하게 조정할 수 있도록 하는 것.
다양한 행동 패턴을 사용하면 객체간의 결합도를 낮추고 재사용과 유연성을 향상할 수 있다.
생성패턴 은 말그대로 객체의 "생성"에 포커싱이 되었다면, 행동패턴 은 객체의 "행동" 다른 말로는 통신에 포커싱이 되어있는 패턴이라고 생각하면 된다.
전략패턴 이란? (Strategy Pattern)
실행중 알고리즘을 선택할 수 있게 하는 행위 소프트웨어 디자인 패턴이다.
- 특정한 계열의 알고리즘들을 정의하고
- 각 알고리즘을 캡슐화하며
- 이 알고리즘들을 해당 계열 안에서 상호교체가 가능하게 만든다.
전략은 유연하고 재사용 가능한 객체지향 소프트웨어를 어떻게 설계하는지 기술하기 위해 작성된 디자인패턴 중 하나이다.
제공된 간단한 UML을 확인했을 때 음 하나의 프로그램 실행 단위에서 인터페이스를 구현하는 객체들을 특정 시간대에 서로 다른 객체를 호출하는구나라고 생각하고 넘어가자.
구루에 작성된 전략패턴 의 정의를 보면 보다 전략패턴이 명확해진다.
전략패턴 은 알고리즘들의 패밀리 를 정의하고, 각 패밀리를 별도의 클래스에 넣은 후 그들의 객체들을 상호교환할 수 있도록 하는 행동 디자인 패턴입니다.
전략패턴은 객체를 교환가능하게 만들어주는 패턴이구나, 패밀리들을 정의한다 추상화를 한다고 생각하면 되는 걸까?
위키와 구루의 내용을 종합해 보자면
전략패턴은 객체 간의 "통신, 교환 " 가능하며, 이들은 캡슐화되어 특정 객체에 의존적이지 않으며 유연하게 재사용 가능하다.
구루에서 제공된 구조이다.
컨택스트는 오직 Strategy 인터페이스 만을 통해 ConcreteStrategies와 통신을 하고 있다.
Concrete Strategies는 콘텍스트에서 수행될 다양한 알고리즘들을 구현하고 있다.
클라이언트는 Concrete Strategies 중 원하는 구현체를 선택해 콘텍스트에서 원하는 시점에 원하는 방향성을 가지고 구현이 가능하다.
이러한 전략패턴 은 언제 적용되어야 하는가?
- 객체 내에서 한 알고리즘의 다양한 변형들을 사용하고 싶을 때, 런타임 중에 한 알고리즘에서 다른 알고리즘으로 전환하고 싶을 때
- 일부 행동을 실행하는 방식에서만 차이가 있는 유사한 클래스들이 많은 경우
- 알고리즘 즉 수행하고자 하는 변경하고자 하는 사항 들을 세부 로직 과의 결합성을 낮추고 싶을 때
- 알고리즘의 다른 변형들 사이를 전환하는 거대한 조건문이 클래스 내부에 있을 때
Html 또는 마크다운을 선택적으로 클라이언트에서 호출할 수 있는 전략패턴을 작성해 보자.
type OutputFormat int
const (
MarkDown OutputFormat = iota
Html
)
type ListStrategy interface {
Start(builder *strings.Builder)
End(builder *strings.Builder)
AddListItem(builder *strings.Builder, item string)
}
type MarkdownListStrategy struct{}
func (m *MarkdownListStrategy) Start(builder *strings.Builder) {
}
func (m *MarkdownListStrategy) End(builder *strings.Builder) {
}
func (m MarkdownListStrategy) AddListItem(builder *strings.Builder, item string) {
builder.WriteString(" * " + item + "\n")
}
var _ ListStrategy = (*MarkdownListStrategy)(nil)
type HtmlListStrategy struct{}
func (h *HtmlListStrategy) Start(builder *strings.Builder) {
builder.WriteString("<ul>\n")
}
func (h *HtmlListStrategy) End(builder *strings.Builder) {
builder.WriteString("</ul>\n")
}
func (h *HtmlListStrategy) AddListItem(builder *strings.Builder, item string) {
builder.WriteString("\t <li>" + item + "</li>\n")
}
var _ ListStrategy = (*HtmlListStrategy)(nil)
type TextProcessor struct {
builder strings.Builder
list ListStrategy
}
func NewTextProcessor(list ListStrategy) *TextProcessor {
return &TextProcessor{builder: strings.Builder{}, list: list}
}
func (t *TextProcessor) SetOutputFormat(fmt OutputFormat) {
switch fmt {
case MarkDown:
t.list = &MarkdownListStrategy{}
case Html:
t.list = &HtmlListStrategy{}
}
}
func (t *TextProcessor) AppendList(items []string) {
s := t.list
s.Start(&t.builder)
for _, item := range items {
s.AddListItem(&t.builder, item)
}
s.End(&t.builder)
}
func (t *TextProcessor) Reset() {
t.builder.Reset()
}
func (t *TextProcessor) String() string {
return t.builder.String()
}
리스트 전략 인터페이스를 구성해 전략패턴을 적용한다.
문장의 시작과 끝을 나타내는 함수와, 어떠한 아이템들이 추가되는지에 대한 인터페이스를 정의했다.
마크다운과 Html 은 전략패턴의 구현체가 있으며 Text 프로세스에 의해 어떠한 형태로 데이터가 기입되는지 결정된다.
결과는 아래와 같다.
func Test_02(t *testing.T) {
tt := NewTextProcessor(&MarkdownListStrategy{})
tt.AppendList([]string{"park", "gui", "woo"})
fmt.Println(tt)
tt.Reset()
tt.SetOutputFormat(Html)
tt.AppendList([]string{"park", "gui", "woo"})
fmt.Println(tt)
}
/**
=== RUN Test_02
* park
* gui
* woo
<ul>
<li>park</li>
<li>gui</li>
<li>woo</li>
</ul>
*/
실행 시 이런 결과 값이 발생한다.
전략 패턴은 단순하다. 클라이언트가 원하는 시점에 특정 객체의 원하는 행동을 지정할 수 있다.
알고리즘 이라고 거창하게 되어 있지만 클라이언트 의 호출자 에 의해 프로그램 실행중에 로직의 변경이 필요하다면 전략패턴 은 훌륭한 해결책이 될수 있다.
기존 회사 프로젝트 의 예로 api 호출 grpc 호출 등 모든 서비스 들은 Service interface 에 의해 구현되고 호출된다.
각 라우터들은 저 Service 인터페이스를 구현하고 특정 라우터의 호출 마다 매번 실행되는 서비스 들은 교체 되어 실행된다 라우터 의 구현체 에 의해 교체 된다는 점에서 전략 패턴이 적용되었다고 볼수 있다.
'Go > Design Pattern' 카테고리의 다른 글
[Design Pattern] 구조패턴-데코레이터 패턴 (Decorator Pattern) (0) | 2023.07.10 |
---|---|
[Design Pattern] 행동패턴-옵저버패턴 (Observer Pattern) (0) | 2023.07.03 |
[Design Pattern] 생성패턴 (Singleton Pattern) (0) | 2023.05.10 |
[Design Pattern] 생성패턴 (Prototype Pattern) (0) | 2023.05.08 |
[Design Pattern] 생성패턴 (Builder Pattern) (0) | 2023.04.10 |