어떤 객체를 직접적으로 사용하는 것이 아니라, 그 객체를 대신하는 프록시(대리인) 객체를 앞에 두어 호출을 가로채는 방식
- Subject (인터페이스) : IMonster
- Real Subject (실제 객체) : ModernMonster
- Proxy : MonsterProxy
#include <iostream> #include <string> // 몬스터의 상태를 나타내는 열거형 클래스 enum class MonsterState { IDLE, ATTACK, RUN }; // 몬스터의 행동을 정의하는 인터페이스 클래스 class IMonster { public: virtual ~IMonster() = default; virtual void Attack(int _useenergy) = 0; virtual void RecoverEnergy(int _addenergy) = 0; }; // 실제 몬스터의 기능을 구현한 클래스 (Real Subject) class ModernMonster : public IMonster { private: std::string name; int attack; int energy; public: ModernMonster(const std::string& _name, int _attack = 100, int _energy = 100) : name(_name), attack(_attack), energy(_energy) {} void Attack(int _useenergy) override { if (energy - _useenergy >= 0) { std::cout << name << " - 공격 : " << attack << std::endl; energy -= _useenergy; } else { std::cout << "기력이 부족합니다." << std::endl; } } void RecoverEnergy(int _addenergy) override { energy += _addenergy; } }; // 몬스터에 대한 접근을 제어하는 프록시 클래스 (Proxy) class MonsterProxy : public IMonster { private: std::shared_ptr<ModernMonster> monster; // 실제 몬스터 객체에 대한 포인터 MonsterState state; // 몬스터의 현재 상태를 제어 public: MonsterProxy(std::shared_ptr<ModernMonster> _monster, const MonsterState& _state) : monster(_monster), state(_state) {}; // 공격 요청을 중계 void Attack(int _useenergy) override { // 상태가 ATTACK일 때만 실제 몬스터의 Attack 함수를 호출 if (state == MonsterState::ATTACK) { monster->Attack(_useenergy); } else { std::cout << "대기,달리는 상태입니다. 공격불가" << std::endl; } } // 에너지 회복 요청을 중계 void RecoverEnergy(int _addenergy) override { // 상태가 IDLE일 때만 실제 몬스터의 RecoverEnergy 함수를 호출 if (state == MonsterState::IDLE) { monster->RecoverEnergy(_addenergy); } else { std::cout << "달리거나 공격중인상태에서는 기력 회복 불가" << std::endl; } } // 프록시가 관리하는 상태를 변경/조회하는 함수 void SetState(const MonsterState& _state) { state = _state; } MonsterState getState() const { return state; } }; int main() { // 실제 몬스터 객체를 생성 std::shared_ptr<ModernMonster> monster = std::make_shared<ModernMonster>("슬라임"); // 실제 몬스터를 제어할 프록시 객체를 생성. 초기 상태는 IDLE MonsterProxy proxy(monster, MonsterState::IDLE); proxy.Attack(70); // IDLE 상태이므로 공격 불가 proxy.SetState(MonsterState::ATTACK); // 상태를 ATTACK으로 변경 proxy.Attack(70); // ATTACK 상태이므로 공격 가능 proxy.Attack(70); // 기력이 부족하여 공격 불가 proxy.RecoverEnergy(10); // ATTACK 상태이므로 회복 불가 proxy.SetState(MonsterState::IDLE); // 상태를 IDLE로 변경 proxy.RecoverEnergy(50); // IDLE 상태이므로 회복 가능 proxy.RecoverEnergy(50); // IDLE 상태이므로 회복 가능 return 0; }
- 인터페이스 공유 : 실제 객체(ModernMonster)와 프록시(MonsterProxy)가 모두 동일한 인터페이스(IMonster)를 구현합니다. 덕분에 main 함수와 같은 클라이언트 코드에서는 실제 객체를 쓰든 프록시를 쓰든 동일한 방식으로 코드를 작성할 수 있다.
- 접근 제어 : MonsterProxy는 ModernMonster의 메서드를 바로 호출해주지 않는다. 대신, 자신이 가진 state 변수의 값을 먼저 확인하고, 조건이 맞을 때만 실제 객체에게 요청을 전달
- 부가 기능 : 이 예제에서는 '상태에 따른 접근 제어'라는 부가 기능을 추가했지만, 프록시 패턴은 네트워크 통신, 로깅, 캐싱 등 다양한 부가 기능을 추가하는 데 사용될 수 있다.