728x90
🎯 의도
- 연산을 적용할 원소의 클래스를 변경하지 않고도 새로운 연산을 정의 할 수 있습니다.
📜 구현방법
- 인터페이스 : 방문자(Visitor), 수락자(Acceptor)
방문자(Visitor) : 방문자는 다양한 수락자를 받아들이는 visit 인터페이스를 상속받고, 다형성을 갖도록 합니다. 그리고 각각의 다형성이 있는 함수안에서 기능들을 구현합니다.
요소(Elememt) : 새로운 기능을 추가할 클래스는 accpet 인터페이스를 상속받아 방문자(자기자신을 전달하여)에게 위임합니다.
🖥️ 코드
아래의 해더파일은 방문자와 수락자에 대한 인터페이스를 정의합니다.
ComputerPartVisitor는 방문자로 visit 함수를 정의하고 여러 요소들을 방문 할 수 있게 다형성으로 인터페이스를 정의합니다.
ComputerPart는 요소로 방문자에게 위임하기위한 인터페이스를 정의합니다.
#ifndef COMPOENT_INTERFACE
#define COMPOENT_INTERFACE
#include <iostream>
using namespace std;
// Forward declaration
class Computer;
class Keyboard;
class Monitor;
class Mouse;
// Visitor Interface
class ComputerPartVisitor {
public:
virtual void visit(Computer &computer) = 0;
virtual void visit(Keyboard &keyboard) = 0;
virtual void visit(Monitor &monitor) = 0;
virtual void visit(Mouse &mouse) = 0;
virtual ~ComputerPartVisitor() {}
};
// Element Interface
class ComputerPart {
public:
virtual void accept(ComputerPartVisitor &visitor) = 0;
virtual ~ComputerPart() {}
};
#endif
ComputerPartDisplayVisitor는 방문자 인터페이스를 구현합니다. 요소에서 방문자에게 위임을 하여 방문자는 기능에 대한 구현을 합니다.
#include "ComponentInterface.hpp"
class ComputerPartDisplayVisitor : public ComputerPartVisitor {
public:
void visit(Computer &computer) override {
cout << "Displaying Computer." << endl;
}
void visit(Keyboard &keyboard) override {
cout << "Displaying Keyboard." << endl;
}
void visit(Monitor &monitor) override {
cout << "Displaying Monitor." << endl;
}
void visit(Mouse &mouse) override {
cout << "Displaying Mouse." << endl;
}
};
새로운 기능을 추가하기위해 ComputerPart 인터페이스를 구현합니다. 구현방법은 동작을 방문자에게 위임합니다. 여기서 자기자신의 인스턴스를 전달합니다.
#include "ComponentInterface.hpp";
class Keyboard : public ComputerPart {
public:
void accept(ComputerPartVisitor &visitor) override {
visitor.visit(*this);
}
};
class Monitor : public ComputerPart {
public:
void accept(ComputerPartVisitor &visitor) override {
visitor.visit(*this);
}
};
class Mouse : public ComputerPart {
public:
void accept(ComputerPartVisitor &visitor) override {
visitor.visit(*this);
}
};
class Computer : public ComputerPart {
ComputerPart *parts[3];
public:
Computer() {
parts[0] = new Keyboard();
parts[1] = new Monitor();
parts[2] = new Mouse();
}
void accept(ComputerPartVisitor &visitor) override {
for (auto &part : parts) {
part->accept(visitor);
}
visitor.visit(*this);
}
~Computer() {
for (auto &part : parts) {
delete part;
}
}
};
ComputerPartVisitor를 생성하여 accept 하여 KeyBoard, Mouse, Monitor, Computer에 대한 기능을 클래스의 변경없이 위임하여 동작하도록 만들 수 있습니다.
#include "ConcreateComponent.hpp"
#include "ConcreateVisitor.hpp"
int main() {
ComputerPart *computer = new Computer();
ComputerPartVisitor *visitor = new ComputerPartDisplayVisitor();
computer->accept(*visitor);
delete visitor;
delete computer;
return 0;
}
💁 장/단점
장점 :
- 개방/폐쇄 원칙. 당신은 다른 클래스를 변경하지 않으면서 해당 클래스의 객체와 작동할 수 있는 새로운 행동을 도입할 수 있습니다.
- 단일 책임 원칙. 같은 행동의 여러 버전을 같은 클래스로 이동할 수 있습니다.
- 비지터 객체는 다양한 객체들과 작업하면서 유용한 정보를 축적할 수 있습니다. 이것은 객체 트리와 같은 복잡한 객체 구조를 순회하여 이 구조의 각 객체에 비지터 패턴을 적용하려는 경우에 유용할 수 있습니다.
단점:
- 클래스가 요소 계층구조에 추가되거나 제거될 때마다 모든 비지터를 업데이트해야 합니다.
- 비지터들은 함께 작업해야 하는 요소들의 비공개 필드들 및 메서드들에 접근하기 위해 필요한 권한이 부족할 수 있습니다.
728x90
'디자인패턴' 카테고리의 다른 글
상태(State) 패턴 (0) | 2024.03.16 |
---|