프록시 패턴
프록시는 대리인이라는 뜻으로, 무엇인가를 대신 처리하는 의미이다.
일종의 비서라고 생각하면 쉽다. 사장실에 바로 들어가서 사장님을 바로 만나는 게 아닌 비서를 통해 사장님을 만나는 개념이라 생각할 수 있다.
어떤 객체를 사용하고자 할 때, 객체를 직접 참조하는 것이 아니라 해당 객체를 대행하는 객체를 통해 대상 객체에 접근하는 방식을 사용하면 해당 객체가 메모리에 존재하지 않아도 기본적인 정보를 참조하거나 설정할 수 있고, 실제 객체의 기능이 반드시 필요한 시점까지 객체의 생성을 미룰 수 있다.
프록시가 사용되는 대표적인 3가지
가상프록시
꼭 필요로 하는 시점까지 객체의 생성을 연기하고, 해당 객체가 생성된 것처럼 동작하도록 만들고 싶을 때 사용하는 패턴이다. 프록시 클래스에서 자잘한 작업들을 처리하고 리소스가 많이 요구되는 작업들이 필요할 때에만 주체 클래스를 사용하도록 구현한다.
원격프록시
원격 객체에 대한 접근을 제어 로컬 환경에 존재하며, 원격객체에 대한 대변자 역할을 하는 객체 서로 다른 주소 공간에 있는 객체에 대해 마치 같은 주소 공간에 있는 것처럼 동작하게 만드는 패턴이다.
보호프록시
주체 클래스에 대한 접근을 제어하기 위한 경우에 객체에 대한 접근 권한을 제어하거나 객체마다 접근 권한을 달리하고 싶을 때 사용하는 패턴으로 프록시 클래스에서 클라이언트가 주체 클래스에 대한 접근을 허용할지 말지 결정하도록 할 수가 있다
프록시 패턴을 사용하는 이유
- OCP를 지킬 수 있다 - 기존 코드를 변경하지 않고 새로운 기능을 추가할 수 있다.
- SRP를 지킬 수 있다 - 기존 코드가 해야 하는 일만 유지할 수 있다.
- 유연한 코드를 만들 수 있다 - 객체 초기화 지연 및 기능 추가, 흐름제어 등으로 다양하게 활용할 수 있다.
프록시 패턴 사용 예시
사이즈가 큰 이미지와 텍스트가 있는 문서를 본다고 가정했을 때, 이미지와 텍스트가 모두 로딩되고 보이는 것보다는, 텍스트라도 더 빠르게 로딩되어 보이는 것이 좋다. 즉 텍스트 처리용 프로세서와 이미지 처리용 프로세스를 별도로 운영하면 된다.
이러한 구조를 갖도록 설계하는 것이 프록시 패턴이다.
public interface Image {
void displayImage();
}
public class RealImage implements Image{
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}
private void loadFromDisk(String fileName) {
System.out.println("Loading " + fileName);
}
@Override
public void displayImage() {
System.out.println("Displaying " + fileName);
}
}
실제 이미지 객체이다.
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void displayImage() {
// 객체의 초기화를 지연시켜 실제로 사용될 때 생성함으로써 메모리 절약
if (realImage == null){
realImage = new RealImage(fileName);
}
realImage.displayImage(); // 프록시가 RealImage()의 메소드를 호출
}
}
프록시 이미지 객체이다. 객체 초기화를 지연시킬 수 있다.
public class Main {
public static void main(String[] args) {
Image image1 = new ProxyImage("test1.png");
Image image2 = new ProxyImage("test2.png");
image1.displayImage();
System.out.println();
image1.displayImage();
System.out.println();
image2.displayImage();
//Loading test1.png
//Displaying test1.png
//
//Displaying test1.png
//
//Loading test2.png
//Displaying test2.png
}
}
프록시 패턴의 장단점
장점
- 사이즈가 큰 객체가 로딩되기 전에도 프록시를 통해 참조를 할 수 있다.
- 기존 객체를 수정하지 않고 일련의 로직을 프록시 패턴을 통해 추가할 수 있다.
- 실제 객체를 수행하기 이전에 전처리를 하거나, 기존 객체를 캐싱할 수 있다.
- 실제 객체의 public, protected 메서드들을 숨기고 인터페이스를 통해 노출시킬 수 있다.
- 로컬에 있지 않고 떨어져 있는 객체를 사용할 수 있다.
단점
- 객체를 생성할 때 한 단계를 거치게 되므로, 빈번한 객체 생성이 필요한 경우 성능이 저하될 수 있다.
- 프록시 내부에서 객체 생성을 위해 스레드가 생성, 동기화가 구현되야 하는 경우 성능이 저하될 수 있다.
- 로직이 난해해져 가독성이 떨어질 수 있다.
정리
프록시 패턴은 객체의 인터페이스를 유지하면서 객체에 대한 간접적인 접근을 제공하므로,
클라이언트 코드는 프록시 객체를 사용할 때 원본 객체와 동일한 방식으로 상호작용할 수 있다.
이로 인해 코드의 유연성과 재사용성을 높일 수 있다.
'CS' 카테고리의 다른 글
트랜잭션과 잠금 (0) | 2023.09.26 |
---|---|
이터레이터 패턴(Iterator Pattern) (0) | 2023.05.16 |
옵저버 패턴(Observer Parttern) (0) | 2023.05.11 |
전략 패턴(Strategy Pattern) (0) | 2023.05.10 |
팩토리 메소드 패턴(Factory Method Pattern) (0) | 2023.04.29 |