프록시 패턴이란, 특정 객체에 접근하고자 할 때 직접 접근하는 것이 아니라 대리자를 통해 접근하도록 하는 패턴이다.
프록시 패턴 (대리자 패턴)
아래의 코드를 보자.
class A
{
public:
void Death() {}
void Attack() {}
}
int main()
{
A* NewA = new A():
if(NewA != nullptr)
{
NewA->Attack();
}
if(NewA != nullptr)
{
NewA->Death();
delete NewA;
NewA = nullptr;
}
return 0;
}
먼저, A객체를 동적으로 생성해주었다.
이후, nullptr체크를 한 뒤 Attack함수를 호출해 주었다.
다음으로, nullptr체크를 한 뒤, Death함수를 호출한 뒤, NewA의 메모리를 해제하고 NewA가 가리키는 포인터를 nullptr로 변경해주었다.
이 코드에서 문제점을 찾아보자.
1. A객체를 알아야 한다.
2. 매번 nullptr 검사를 해주어야 한다.
3. 실제로 객체의 기능을 사용하기 이전부터 객체가 메모리에 존재한다.
A객체를 생성하고 그 멤버함수를 호출하기 위해선 당연히 A객체를 알아야 한다.
현재는 main함수에서 A객체의 멤버함수를 호출하고 있지만, 만약 B라는 다른 객체에서 A의 멤버함수를 호출하게 된다면 A객체와 B객체간의 결합도가 높아진다고 할 수 있다.
또한, A객체를 값으로 알고 있는 것이 아니라 주소값으로 알고 있기 때문에, 주소값에 접근할 때마다 nullptr검사 등의 유효성 검사를 매번 해주어야 한다. 이는 프로그래머 입장에선 상당히 번거로운 일이라고 할 수 있다.
또한, NewA가 실제로 사용되기 이전부터 객체를 생성하여 메모리에 존재하게 되는데, 위의 코드에선 생성한 뒤 바로 Attack함수를 호출하고 있지만, 그 시기가 늦어진다면 Attack 함수가 호출되기 이전까지 의미없는 데이터가 메모리 용량을 차지하고 있게 되는 것이다.
이러한 문제점들을 해결하기 위해 프록시 패턴을 사용할 수 있다.
아래의 코드를 보자.
class A
{
public:
void Death() {}
void Attack() {}
};
class AProxy
{
public:
void Attack()
{
if(NewA == nullptr)
{
NewA = new A();
}
NewA->Attack();
}
void Death()
{
if(NewA == nullptr)
{
std::cout << "A객체가 생성되지도 않았는데, 파괴하려 하였습니다." << std::endl;
return;
}
NewA->Death();
delete NewA;
NewA = nullptr;
}
private:
A* NewA = nullptr;
};
int main()
{
AProxy* NewProxy = new AProxy();
NewProxy->Attack();
NewProxy->Death();
return 0;
}
A의 기능을 사용하기 위해, A의 멤버함수를 직접 호출하는 것이 아니라 AProxy의 멤버함수를 호출하고 있다.
AProxy는 내부에서 A의 기능에 필요한 전처리를 한 뒤 A의 함수를 호출하고 있으며, 함수가 끝난 뒤 후처리가 필요하다면 후처리 또한 실행해주고 있다.
이로 인해, A의 기능을 사용할 때 매번 번거롭게 nullptr 검사 등의 전처리 코드를 작성할 필요가 없어지며, A의 객체를 직접 몰라도 AProxy 객체를 통해 A의 기능을 사용할 수 있게 된다. 이로 인해, A객체와 낮은 결합도를 유지한 채로 기능을 사용할 수 있게 된다.
또한, 전처리 과정에서 A 객체의 기능을 사용하고자 하는 객체의 권한을 파악하여 접근 허용 여부를 판별하게 되면, 보안 측면의 이점도 노려볼 수 있다.
또한, AProxy의 Attack함수가 호출될 때 A객체를 생성하기 떄문에 A 객체의 생성 시점을 최대한 미룰 수 있으며, 이로 인해 조금 더 효율적인 메모리 사용이 가능해진다.
이처럼 A에 직접 접근하여 기능을 사용하지 않고, 다른 객체를 한 단계 거쳐서 A의 기능을 사용하는 디자인 패턴이 프록시 패턴이다.
프록시 패턴에는 위와 같은 장점들이 있지만, 단점도 분명 존재한다.
1. 함수 호출 과정에 한 단계가 추가되는 만큼, 성능이 하락할 수 있다.
2. A객체 뿐만 아니라 AProxy 객체도 메모리에 존재해야 하므로, 메모리 사용량 측면에선 비효율적일 수 있다.
3. 함수 호출 과정에 한 단계가 추가되는 만큼, 코드가 복잡해지고 가독성이 떨어질 수 있다.
프록시 패턴의 장단점
장점 |
1. 객체 생성 시점을 뒤로 미룰 수 있다. |
2. 전처리, 후처리 등을 기능과 묶어 사용할 수 있다. |
3. 객체 간의 결합도를 낮출 수 있다. |
4. 보안성을 향상시킬 수 있다. |
단점 |
1. 메모리 사용량이 증가한다. |
2. 속도 측면의 성능이 하락할 수 있다. |
3. 코드가 복잡해지고 가독성이 저하될 수 있다. |
'C++ > 디자인 패턴' 카테고리의 다른 글
디자인 패턴 - 발행 구독 패턴 (Pub - Sub pattern) (0) | 2024.05.22 |
---|---|
디자인 패턴 - 컴포넌트 패턴 (0) | 2024.04.21 |
디자인 패턴 - 팩토리 메서드 패턴, 추상 팩토리 패턴 (0) | 2024.04.02 |
디자인 패턴 - 싱글 톤 패턴 (1) | 2024.04.02 |