본문 바로가기

CS/디자인 패턴

Visitor Pattern 방문자 패턴

방문자 패턴이란?


알고리즘을 객체 구조에서 분리시키는 디자인 패턴(행위 패턴)

구조를 수정하지 않고 새로운 동작을 기존 객체에 추가할 수 있다.

(연산을 적용할 객체의 클래스를 변경하지 않고도 새로운 연산을 정의할 수 있다.)

클래스에서 객체를 다루는 기능을 내부 메소드로 구현하는 것이 아닌, 각 클래스들의 데이터 구조에서 처리 기능을 분리하여 별도의 클래스로 구현하는 패턴이다.

분리된 처리 기능은 Visitor를 통해 각 클래스들을 방문하면서 수행한다.

즉, 실제 로직을 가지고 있는 객체가 로직을 적용할 객체를 방문하면서 실행하는 패턴이다. (로직과 구조를 분리하는 패턴)

 

※ 비지터 객체는 Traverser 객체와 함께 돌아간다.

  • 트래버서는 컴포지트 패턴을 쓸 때, 복합 객체 내에 속해 있는 모든 객체에 접근하는 일을 도와주는 역할을 한다.
  • 비지터 객체에서 복합 객체 내의 모든 객체를 대상으로 원하는 작업을 처리하게 해준다.
  • 각각의 상태를 모두 가져오면 클라이언트는 비지터에게 각 상태에 맞는 다양한 작업을 처리하도록 요구할 수 있다.
  • 새로운 기능이 필요하게 되더라도 비지터만 고치면 되기에 편리하다.

 

장점

  • 구조를 변경하지 않으면서도 복합 객체 구조에 새로운 기능을 추가할 수 있다.
  • 비지터가 수행하는 기능과 관련된 코드를 한곳에 모아둘 수 있다.

단점

  • 새로운 작업 대상이 추가될 때마다 방문자 로직을 추가해야 한다.
  • 방문자와 작업 대상의 결합도가 높아진다.

 

https://jhtop0419.tistory.com/114

IVisitor

  • 방문자 인터페이스로 visit(Element) 메소드를 공용 인터페이스로 사용. (Element = 작업 대상)

IElement

  • 작업 대상 클래스의 인터페이스로 accept(Visitor) 메소드를 공용 인터페이스로 사용. (Visitor  = 방문자)
  • 내부적으로 Visitor.visit(this)를 호출한다.

 

적용 상황

  • 데이터와 알고리즘을 분리할 때. (코드의 응집도를 높이고자 할 때)
  • 데이터 구조보다 알고리즘이 더 자주 바뀔 때.
  • 적용해야 할 대상 객체가 잘 바뀌지 않을 때. ※ 특히 개수
  • 적용할 알고리즘이 추가될 가능성이 많은 상황일 때.

 

사용예시


IVisitor Interface

public interface IVisitor {

	public void visit(IElement element);
}

 

VisitorA Class

public class VisitorA implements IVisitor {

	@Override
	public void visit(IElement element) {
		if(element instanceof ElementA) {
			System.out.println("VisitorA : " + element.getClass());
		} //
		else {
			System.out.println("element는 ElementA 객체가 아닙니다.");
		}
	}
}

 

VisitorB Class

public class VisitorB implements IVisitor {

	@Override
	public void visit(IElement element) {
		if(element instanceof ElementB) {
			System.out.println("VisitorB : " + element.getClass());
		} //
		else {
			System.out.println("element는 ElementB 객체가 아닙니다.");
		}
	}
}

 

IElement Interface

public interface IElement {

	public void accept(IVisitor visitor);
}

 

ElementA Class

public class ElementA implements IElement {

	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}

 

ElementB Class

public class ElementB implements IElement {

	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}

 

Main Class

public class Main {

	public static void main(String[] args) {
		
		IElement elementA = new ElementA();
		IElement elementB = new ElementB();
		
		elementA.accept(new VisitorA());
		elementB.accept(new VisitorB());

		elementA.accept(new VisitorB());
		elementB.accept(new VisitorA());
	}
}

 

 

메소드를 통해 기능을 수행하는 것이 아닌 기능을 수행하는 클래스에서 객체를 넘겨 받아 기능을 수행한다.

(기능을 클래스로 따로 구현)

 

'CS > 디자인 패턴' 카테고리의 다른 글

Facade Pattern 퍼사드 패턴  (0) 2022.10.12