반응형
프록시 패턴 (Proxy Pattern)
1. 정의
프록시 패턴은 어떤 객체에 대한 접근을 제어하기 위해 그 객체의 대리인 역할을 하는 객체를 제공하는 디자인 패턴입니다. 이 패턴은 원본 객체에 대한 접근을 제어하거나, 원본 객체를 감싸서 추가적인 기능을 제공할 수 있습니다. 프록시 객체는 실제 객체와 동일한 인터페이스를 구현하며, 클라이언트는 원본 객체 대신 프록시 객체와 상호작용하게 됩니다.
프록시 패턴은 특히 다음과 같은 경우에 유용합니다:
- 실제 객체의 생성이나 접근에 비용이 많이 들 때
- 원본 객체에 대한 접근을 제한하거나 제어해야 할 때
- 원본 객체에 대한 추가적인 기능(캐싱, 로깅 등)을 구현해야 할 때
2. 목적
- 접근 제어: 프록시 객체를 통해 원본 객체에 대한 접근을 제어할 수 있습니다. 원본 객체에 직접 접근하는 것이 위험하거나 비용이 많이 들 경우, 프록시가 이를 대신 처리합니다.
- 지연 로딩 (Lazy Loading): 실제 객체가 필요할 때까지 객체 생성을 지연시킬 수 있습니다. 즉, 객체가 꼭 필요하지 않다면, 미리 생성하지 않고 요청이 있을 때만 생성합니다.
- 추가적인 기능 제공: 프록시 객체는 원본 객체를 감싸서 로깅, 접근 제어, 캐싱 등의 기능을 추가로 제공할 수 있습니다.
3. 프록시 패턴의 종류
- 가상 프록시 (Virtual Proxy): 원본 객체의 생성이 비용이 많이 드는 경우, 객체 생성이나 접근을 지연시켜 필요할 때만 객체를 생성합니다. 예를 들어, 이미지 로딩과 같은 경우 실제로 화면에 나타나기 전까지 객체 생성이 지연될 수 있습니다.
- 보호 프록시 (Protection Proxy): 원본 객체에 대한 접근 권한을 제어합니다. 사용자나 클라이언트가 원본 객체에 접근할 때, 권한에 따라 접근을 제한할 수 있습니다.
- 캐싱 프록시 (Caching Proxy): 원본 객체의 결과를 캐싱하여 성능을 개선합니다. 동일한 요청이 반복될 때, 원본 객체에 다시 접근하지 않고 캐싱된 값을 반환합니다.
- 스마트 프록시 (Smart Proxy): 원본 객체에 접근하는 데 추가적인 행동을 취하는 프록시로, 예를 들어 원본 객체에 접근할 때마다 참조 횟수를 기록하는 등의 기능을 제공할 수 있습니다.
4. 사용 예시
프록시 패턴은 다양한 상황에서 사용될 수 있습니다:
- 원격 객체에 접근하는 경우 (Remote Proxy): 네트워크를 통해 원격 객체에 접근할 때, 원본 객체와 동일한 인터페이스를 제공하는 프록시를 사용하여 네트워크 통신을 처리합니다.
- 비용이 많이 드는 객체의 지연 초기화 (Lazy Initialization): 예를 들어, 큰 이미지 파일을 로딩할 때 실제로 이미지가 필요한 시점에만 로딩하는 가상 프록시를 사용할 수 있습니다.
- 원본 객체의 접근 권한 제어: 민감한 데이터에 접근할 때 보호 프록시를 사용하여 사용자 권한에 따라 접근을 제한할 수 있습니다.
5. 구현 방법
프록시 패턴은 원본 객체와 동일한 인터페이스를 구현하는 프록시 객체를 통해 원본 객체로의 접근을 제어합니다. 아래는 자바에서 가상 프록시를 구현한 간단한 예시입니다.
// 1. 원본 객체 인터페이스
interface Image {
void display();
}
// 2. 실제 객체 (원본 객체)
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk(); // 실제 이미지 로드
}
private void loadFromDisk() {
System.out.println("Loading " + filename);
}
@Override
public void display() {
System.out.println("Displaying " + filename);
}
}
// 3. 프록시 객체
class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename); // 실제 객체 생성은 필요할 때만 수행
}
realImage.display();
}
}
// 4. 클라이언트 코드
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_image.jpg");
// 이미지가 실제로 로드되지 않음
System.out.println("Image object created, but not loaded.");
// 이미지가 필요할 때만 실제로 로드
image.display(); // 이미지 로딩 및 표시
image.display(); // 두 번째 호출에서는 캐싱된 이미지 사용
}
}
6. 동작 설명
- Image 인터페이스는 원본 객체와 프록시 객체가 구현하는 공통 인터페이스입니다.
- RealImage 클래스는 실제 이미지 파일을 로드하고 출력하는 원본 객체입니다.
- ProxyImage 클래스는 프록시 객체로, 실제 이미지가 필요할 때까지 객체 생성을 지연시킵니다. 이미지를 처음 요청할 때만 실제로 이미지를 로드하고 이후 호출에서는 로드된 객체를 사용합니다.
7. 장점
- 지연 로딩 (Lazy Initialization): 실제 객체가 필요할 때까지 객체 생성을 지연시킬 수 있어 성능을 최적화할 수 있습니다.
- 접근 제어: 프록시 패턴을 통해 원본 객체에 대한 접근을 제어하거나, 접근 권한을 설정할 수 있습니다.
- 추가적인 기능 제공: 프록시를 통해 로깅, 캐싱, 권한 검사 등의 추가 기능을 구현할 수 있습니다.
8. 단점
- 프록시 클래스의 추가 비용: 프록시 패턴을 사용하면 원본 객체 외에도 추가적인 프록시 클래스가 필요하므로, 코드가 복잡해지고 유지보수 비용이 증가할 수 있습니다.
- 지연 성능 문제: 실제 객체 생성이 지연되므로, 프록시가 성능을 개선할 수 있지만, 경우에 따라서는 지연으로 인해 성능 저하가 발생할 수 있습니다.
- 클라이언트와 프록시 객체 간의 결합: 클라이언트는 프록시 객체와 상호작용하지만, 프록시가 실제로 원본 객체와 동일하게 동작해야 하므로 프록시 클래스와 원본 클래스가 밀접하게 결합될 수 있습니다.
9. 프록시 패턴이 유용한 경우
- 원격 객체와의 통신: 원격 서버에 있는 객체와 통신해야 할 때, 네트워크 연결을 관리하는 원격 프록시를 사용하면 편리합니다.
- 비용이 큰 객체의 지연 로딩: 자원이 많이 드는 객체의 생성 시점을 지연시키거나 필요할 때만 로드하는 가상 프록시가 유용합니다.
- 접근 제어가 필요한 경우: 민감한 데이터나 시스템 리소스에 대한 접근을 제어하기 위해 보호 프록시를 사용할 수 있습니다.
- 캐싱이 필요한 경우: 데이터 요청이 자주 발생하고 동일한 결과가 반복되는 경우 캐싱 프록시를 통해 성능을 개선할 수 있습니다.
프록시 패턴은 객체에 대한 접근을 제어하거나, 지연 로딩, 로깅, 권한 검사 등의 기능을 제공하는 데 매우 유용한 패턴입니다. 특히, 원본 객체와 동일한 인터페이스를 유지하면서 다양한 추가 기능을 동적으로 구현할 수 있다는 점에서 많은 상황에 적용할 수 있습니다.
반응형
'언어 > Java' 카테고리의 다른 글
[ Java ] Strategy Pattern - 전략 패턴 알아보기 (0) | 2024.10.03 |
---|---|
[ Java ] Observer Pattern - 옵저버 패턴 알아보기 (3) | 2024.10.03 |
[ Java ] Decoration Pattern - 데코레이션 패턴 알아보기 (0) | 2024.10.03 |
[ Java ] Builder Pattern - 빌더 패턴 알아보기 (1) | 2024.10.03 |
[ Java ] Prototype Pattern - 프로토타입 패턴 알아보기 (0) | 2024.10.03 |