Visitor Pattern?
- 방문자 패턴(Visitor Pattern) : 알고리즘을 객체 구조에서 분리시키는 디자인 패턴이다.
- 분리를 하게 되면, 구조를 수정하지 않고 새로운 동작을 기존 객체에 추가할 수 있다!!
-> 개방 폐쇄 원칙을 적용하게 된다!
Why Visitor Pattern?
- 데이터 구조와 연산을 분리 하여 인스턴스 필드를 변경하지 않고 새로운 연산을 추가할 수 있기 때문이다!
- 한마디로, domain에게 View를 위한 책임은 Visitor에게 위임하기 위해서 사용된다!
- 새로운 연산을 더 만들고 싶다면, 새로운 방문자를 추가하면 된다!
패턴 적용
Car Interface 구현
* Car Interface를 구현해보자!
package visitor.domain;
import visitor.visitor.ViewVisitor;
public interface Car {
int drive();
int getFuel();
}
- drive = 기름을 소모해 운전하는 메서드
- getFuel = 기름을 조회하는 메서드
* 인터페이스가 있으니 이것을 바탕으로 Bus를 만들어보자!
package visitor.domain;
public class Bus implements Car {
private int fuel;
Bus(final int fuel) {
this.fuel = fuel;
}
@Override
public int drive() {
return --fuel;
}
@Override
public int getFuel() {
return fuel;
}
}
Bus, Truck은 편의상 기능을 같게 했다
기름을 주입해서, 달리는 기능을 추가했다! ( 예외 처리는 일부러 생략했다 = 코드 길어질까봐 )
* 방문자 패턴을 적용하기 위해서는 아래와 같이 인터페이스에 메서드 한 줄을 추가해야 된다!
package visitor.domain;
import visitor.visitor.ViewVisitor;
public interface Car {
int drive();
int getFuel();
String visit(ViewVisitor viewVisitor);
}
Car 인터페이스 추가된 메서드
package visitor.domain;
import visitor.visitor.ViewVisitor;
public class Bus implements Car {
private int fuel;
Bus(final int fuel) {
this.fuel = fuel;
}
@Override
public int drive() {
return --fuel;
}
@Override
public int getFuel() {
return fuel;
}
@Override
public String visit(final ViewVisitor viewVisitor) {
return viewVisitor.visit(this);
}
}
Bus 클래스에 추가된 메서드
viewVisitor에게 자기 자신을 인자로 넘겨서 책임을 위임하는 모습이다!
Visitor Interface 구현
* 그러면 방문자 인터페이스도 구현해보자!
package visitor.visitor;
import visitor.domain.Bus;
import visitor.domain.Truck;
public interface ViewVisitor {
String visit(Bus bus);
String visit(Truck truck);
}
* 바로 인터페이스를 실체화하자!
package visitor.visitor;
import visitor.domain.Bus;
import visitor.domain.Truck;
public class CarViewVisitor implements ViewVisitor {
private static final String BUS_STATUS = "현재 버스의 기름 상태 : ";
private static final String TRUCK_STATUS = "현재 트럭의 기름 상태 : ";
@Override
public String visit(final Bus bus) {
return BUS_STATUS + bus.getFuel();
}
@Override
public String visit(final Truck truck) {
return TRUCK_STATUS + truck.getFuel();
}
}
* 버스인지 트럭인지 판단하여, 현재 기름 상태를 보여줄 수 있게 된다!!!
* 코드를 작성했으니, Bus에 대하여 Test를 한번 실시해볼까?
Test code
package visitor.domain;
import org.junit.jupiter.api.Test;
import visitor.visitor.CarViewVisitor;
import static org.assertj.core.api.Assertions.assertThat;
class BusTest {
@Test
void 버스가_운전하고_상태를_제대로_출력하는지_테스트() {
/* Given */
Bus bus = new Bus(10);
/* When */
bus.drive();
/* Then */
assertThat(bus.getFuel()).isEqualTo(9);
assertThat(bus.visit(new CarViewVisitor())).isEqualTo("현재 버스의 기름 상태 : 9");
}
}
- 버스에게 10L의 기름을 주입한다
- 한번 운전을 하고 나면, 기름이 줄게 된다!!
- 방문자 객체를 통해서 현재 상태를 문자열로 가져오게 된다!!
정리
- 정리하자면 방문자 패턴은, 기존 클래스 필드 정보를 유지하면서 새로운 연산을 추가하는 방식이다!
참고
비지터 패턴 - 위키 백과
방문자 패턴(Visitor Pattern)
'Developer > Design Pattern' 카테고리의 다른 글
Template Method Pattern - 템플릿 메소드 패턴 (0) | 2019.06.09 |
---|---|
Observer Pattern - 옵저버 패턴 (0) | 2019.06.09 |
Strategy Pattern - 스트레지 패턴, 전략 (0) | 2019.05.26 |
Singleton Pattern - 싱글톤 패턴 (6) | 2019.05.24 |
Design Pattern - 소개 (2) | 2019.05.24 |