[Design Pattern] 행동 패턴 7. 비지터 (Visitor)
Table of Contents
비지터 (Visitor) #
- 객체의 구조(Component)와 처리(Visitor)를 분리한다.
- 객체 구조의 요소들 위에서 수행되어지는 연산을 표현한다.
- 특징
- 기존 구조를 변경하지 않고 기존 클래스 계층구조에 새로운 행동들을 추가할 수 있도록 한다.
- Visitor는 Component의 필드나 메서드를 사용할 수 있어야 하므로, 접근 권한을 더 많이 공개해야 할 수 있다.
개념적인 예시 #
// 컴포넌트 : 구조가 짜여져 있다.
public interface IComponent
{
void Accept(IVisitor visitor);
}
public class ConcreteComponentA : IComponent
{
// 비지터를 받아들이고
// 비지터의 메서드A를 실행하게 한다.
// 따라서 비지터는 컴포넌트A에 해당하는 동작을 처리한다.
public void Accept(IVisitor visitor)
{
visitor.VisitConcreteComponentA(this);
}
// 베이스 클래스에 없는 메서드도 있다.
// 하지만 비지터는 구체적인 컴포넌트를 알고 있으므로 이 메서드를 사용할 수 있다.
public string ExclusiveMethodOfConcreteComponentA()
{
return "A";
}
}
public class ConcreteComponentB : IComponent
{
public void Accept(IVisitor visitor)
{
visitor.VisitConcreteComponentB(this);
}
public string SpecialMethodOfConcreteComponentB()
{
return "B";
}
}
// 비지터 : 컴포넌트를 방문해서 동작을 처리한다.
// 구체적인 컴포넌트 클래스에 따라 동작한다.
// 새로운 처리를 추가하고 싶다면, 새로운 방문자를 만들고, 컴포넌트에서 방문자를 받아들이게 하면 된다.
public interface IVisitor
{
void VisitConcreteComponentA(ConcreteComponentA element);
void VisitConcreteComponentB(ConcreteComponentB element);
}
class ConcreteVisitor1 : IVisitor
{
public void VisitConcreteComponentA(ConcreteComponentA element)
{
Console.WriteLine("1-");
Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA());
}
public void VisitConcreteComponentB(ConcreteComponentB element)
{
Console.WriteLine("1-");
Console.WriteLine(element.SpecialMethodOfConcreteComponentB());
}
}
class ConcreteVisitor2 : IVisitor
{
public void VisitConcreteComponentA(ConcreteComponentA element)
{
Console.WriteLine("2-");
Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA());
}
public void VisitConcreteComponentB(ConcreteComponentB element)
{
Console.WriteLine("2-");
Console.WriteLine(element.SpecialMethodOfConcreteComponentB());
}
}
public class Client
{
public static void ClientCode(List<IComponent> components, IVisitor visitor)
{
foreach (var component in components)
{
// 클라이언트는 구체적인 컴포넌트 클래스를 몰라도 된다.
component.Accept(visitor);
}
}
}
class Program
{
static void Main(string[] args)
{
List<IComponent> components = new List<IComponent>
{
new ConcreteComponentA(),
new ConcreteComponentB()
};
var visitor1 = new ConcreteVisitor1();
var visitor2 = new ConcreteVisitor2();
// 똑같은 클라이언트 코드로 다양한 비지터를 사용할 수 있다.
Client.ClientCode(components, visitor1); // 1-A, 1-B
Client.ClientCode(components, visitor2); // 2-A, 2-B
}
}