카테고리 없음

비지터패턴

더코드마니아 2023. 3. 22. 14:11

비지터 패턴은 객체지향 프로그래밍 패턴 중 하나로, 주로 데이터 구조와 그 데이터를 처리하는 로직을 분리하고자 할 때 사용합니다. 간단하게 말하면, 여러 종류의 객체에 동작을 적용하려 할 때 비지터 패턴이 유용합니다.

예를 들어, 동물원에서 동물들을 관리한다고 가정해보겠습니다. 동물원에는 여러 종류의 동물이 있고, 이들에게 다양한 활동을 시키고 싶습니다. 이때 비지터 패턴을 사용하면 동물 클래스와 활동 로직을 분리할 수 있습니다.

이렇게 하면 동물에 대한 정보와 활동 로직이 결합되지 않기 때문에, 새로운 동물이나 활동을 추가할 때 기존 코드를 수정하지 않고 확장이 가능합니다.

간단한 비유로, 동물원에서 '방문자'가 차례로 동물들을 방문하며 다양한 활동을 수행한다고 생각할 수 있습니다. 이 방문자는 각 동물에게 어떤 행동을 할지 알고 있으며, 동물들은 방문자가 무슨 일을 하든 신경 쓰지 않습니다.

비지터 패턴을 사용하면 유연성이 높아지지만, 일부 상황에서는 설계가 복잡해질 수도 있습니다. 따라서 프로젝트의 요구 사항에 맞게 적절한 패턴을 선택해야 합니다.

 

아레는 비지터 패턴을 간단한 게임 로직에 비교해서 작성해보았습니다. 

package main

import "fmt"

// GameElement는 방문할 수 있는 게임 요소를 위한 인터페이스
type GameElement interface {
	accept(visitor GameElementVisitor)
}

type Character struct {
	name string
}

type Weapon struct {
	name string
}

func (c *Character) accept(visitor GameElementVisitor) {
	visitor.visitCharacter(c)
}

func (w *Weapon) accept(visitor GameElementVisitor) {
	visitor.visitWeapon(w)
}

// GameElementVisitor는 게임 요소들을 방문할 수 있는 인터페이스
type GameElementVisitor interface {
	visitCharacter(c *Character)
	visitWeapon(w *Weapon)
}

// PrintVisitor는 GameElementVisitor 인터페이스를 구현한 구조체
type PrintVisitor struct{}

// visitCharacter는 PrintVisitor가 Character를 방문하게 합니다.
func (p *PrintVisitor) visitCharacter(c *Character) {
	fmt.Printf("캐릭터: %s\n", c.name)
}

// visitWeapon는 PrintVisitor가 Weapon를 방문하게 합니다.
func (p *PrintVisitor) visitWeapon(w *Weapon) {
	fmt.Printf("무기: %s\n", w.name)
}

func main() {
	gameElements := []GameElement{
		&Character{name: "전사"},
		&Weapon{name: "검"},
		&Character{name: "마법사"},
		&Weapon{name: "지팡이"},
	}

	visitor := &PrintVisitor{}

	for _, element := range gameElements {
		element.accept(visitor)
	}
}

:)