개념공부

디자인 패턴 : 비지터 패턴 (Visitor Pattern)

Cadi 2025. 1. 10. 16:01

Vistor Pattern

  • '방문자'라는 뜻, 방문자는 어떤 장소에 방문했을 때 장소를 변경시키지 않고 정보를 가져옴
  • 특정 객체 구조를 변경시키지 않고 정보를 참고하고 싶을때 사용

구현 

  1.  Ivisitor 인터페이스로 구체적인 요소들에 접근할 visit 함수를 매개변수를 달리해 만듬
  2.  방문을 받고자 하는 요소들을 표시해주기 위해 IElement 인터페이스를 만들고,
     방문 가능한(데이터를 얻고싶은) 클래스들에 인터페이스로 추가
  3. 각 클래스(요소)들은 인터페이스를 상속받아 Ivisitor 타입을 매개변수로 받는 Accept 함수 생성
  4. 구체적 visitor 클래스에서 데이터를 가져와 어떤 가공을 할 지를 정함( 할인과 같은 기능)

 

장점

  • 구체적 클래스(요소)들의 객체 구조를 변화시키지 않음
    IElement를 상속받고, Accept 기능을 추가해야 하긴 하지만, 원래의 '동작' 부분을 변경하진 않음
  • 기존 Element 클래스 변경하지 않고, Visitor를 추가해 같은 데이터로 여러 가공을 할 수 있음
  • 데이터(객체)와 동작(Visitor)의 분리

단점

  • 새로운 Element 추가 시, Visitor 클래스에 추가해줘야함, Element의 확장이 어렵다.
  • 복잡성 증가(단순한 프로젝트 시)

 

사용 이유

 

각 요소들의 데이터를 오픈한다면 ? : 캡슐화 원칙을 위반하게 됨

각 요소들이 직접 데이터를 전달한다면 ? :  객체의 역할이 추가됨, 단일 책임 원칙에 위배

더해서, 확장성에서도 이점이 있다. 예를 들어, 각 요소의 가격들이 있고 이를 가져와 계산하려 할 때 

'할인' 방식과 '기본 방식'으로 계산을 달리해 계산해 클라이언트들에게 전달 가능.

 

예시 코드 

 

public interface IElement
{
    void Accept(IVisitor visitor);
}

public interface IVisitor
{
    void Visit(Book book);
    void Visit(Fruit fruit);
}

 

public class Book : IElement
{
    public string Title { get; }
    public int Price { get; }

    public Book(string title, int price)
    {
        Title = title;
        Price = price;
    }

    public void Accept(IVisitor visitor)
    {
        visitor.Visit(this); // Visitor를 받아들이고 자신의 데이터를 전달
    }
}

public class Fruit : IElement
{
    public string Name { get; }
    public int Weight { get; }

    public Fruit(string name, int weight)
    {
        Name = name;
        Weight = weight;
    }

    public void Accept(IVisitor visitor)
    {
        visitor.Visit(this); // Visitor를 받아들이고 자신의 데이터를 전달
    }
}
public class PriceCalculatorVisitor : IVisitor
{
    private int totalPrice = 0;

    public void Visit(Book book)
    {
        totalPrice += book.Price;
        Console.WriteLine($"Book: {book.Title}, Price: {book.Price}");
    }

    public void Visit(Fruit fruit)
    {
        totalPrice += fruit.Weight * 2; // 예를 들어 과일 무게로 가격 계산
        Console.WriteLine($"Fruit: {fruit.Name}, Calculated Price: {fruit.Weight * 2}");
    }

    public int GetTotalPrice()
    {
        return totalPrice;
    }
}
public class Program
{
    public static void Main()
    {
        List<IElement> elements = new List<IElement>
        {
            new Book("C# Programming", 500),
            new Fruit("Apple", 3),
            new Fruit("Banana", 2)
        };

        PriceCalculatorVisitor visitor = new PriceCalculatorVisitor();

        foreach (var element in elements)
        {
            element.Accept(visitor); // 각 요소가 Visitor를 받아들임
        }

        Console.WriteLine($"Total Price: {visitor.GetTotalPrice()}");
    }
}

 

 

 

요약

 

목적 : 원본 데이터와 객체 구조를 훼손하지 않고, 데이터를 받아와 가공하기 위함

구현 : 데이터를 들고 있는 객체들에게 Element 인터페이스로 Accept 함수 구현하게 해 자신의 데이터 전달.

           Vistor 인터페이스로 요소들을 모두 방문하게 함(매개변수를 달리하며) 

           구체적인 vistor클래스마다 받아올 데이터를 가공하는 방식을 달리함

 

 

참조 : https://velog.io/@newtownboy/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4-%EB%B0%A9%EB%AC%B8%EC%9E%90%ED%8C%A8%ED%84%B4Visitor-Pattern

 

[디자인패턴] 방문자패턴(Visitor Pattern)

Visitor는 사전적인 의미로 어떤 장소에 찾아오는 사람이라는 의미를 갖고 있다. 방문자 패턴에서는 데이터 구조와 처리를 분리한다. 데이터 구조 안을 돌아다니는 주체인 방문자를 나타내는 클

velog.io

 

https://shan0325.tistory.com/41

 

[Design Pattern] Visitor(방문자) 패턴이란?

행위 패턴(Behavioral Pattern) 방문자 패턴(Visitor pattern)은 객체 지향 프로그래밍에서 사용되는 디자인 패턴 중 하나로, 객체의 구조와 그 구조에서 수행되는 작업을 분리하여 구현하는 패턴입니다.

shan0325.tistory.com


https://refactoring.guru/ko/design-patterns/visitor

 

비지터 패턴

/ 디자인 패턴들 / 행동 패턴 비지터 패턴 다음 이름으로도 불립니다: Visitor 의도 비지터(방문자) 패턴은 알고리즘들을 그들이 작동하는 객체들로부터 분리할 수 있도록 하는 행동 디자인 패턴

refactoring.guru

 

'개념공부' 카테고리의 다른 글

클로저(Closure)  (0) 2025.02.12
Unity Event System  (0) 2025.01.25
디자인 패턴 : 프록시 패턴 (Proxy Pattern)  (0) 2025.01.10
디자인 패턴 : 파사드 패턴  (0) 2025.01.09
디자인 패턴 : 컴포지트 패턴  (0) 2025.01.09