-
Proxy Pattern(프록시 패턴)STUDY/디자인패턴 2025. 1. 7. 20:23
프록시 패턴이란?
다른 객체에 대한 대체 또는 자리표시자를 제공할 수 있는 구조 디자인 패턴으로, 원래 객체에 대한 접근을 제어하므로, 클라이언트의 요청이 원래 객체에 전달되기 전 또는 후에 무언가를 수행할 수 있도록 한다.
구조
- ServiceInterface
서비스와 프록시가 구현하는 인터페이스
- Service
어떤 유용한 비즈니스 로직을 제공하는 원본 대상 클래스
- Proxy
서비스 객체를 가리키는 참조 필드가 존재한다. 프록시가 요청의 처리(예: 초기화 지연, 로깅, 액세스 제어, 캐싱 등)를 완료하면, 그 후 처리된 요청을 서비스 객체에 전달한다. 일반적으로 프록시들은 서비스 객체들의 전체 수명 주기를 관리한다.
- Client
같은인터페이스를 통해 서비스들 및 프록시들과 함께 작동해야 한다. 그래야 서비스 객체를 기대하는 모든 코드에 프록시를 전달할 수 있다.
예시
Service Interface
public interface ThirdPartyYouTubeLib { List<Video> listVideos(); Video getVideoInfo(String id); File downloadVideo(String id); }
Service
public class ThirdPartyYouTubeClass implements ThirdPartyYouTubeLib { @Override public List<Video> listVideos() { //... } @Override public Video getVideoInfo(String id) { //... } @Override public File downloadVideo(String id) { //... } }
Proxy
public class YouTubeCacheProxy implements ThirdPartyYouTubeLib { private ThirdPartyYouTubeLib service; private List<Video> cacheList; private HashMap<String, Video> cacheVideo = new HashMap<String, Video>(); private HashMap<String, File> cacheFile = new HashMap<String, File>(); public YouTubeCacheProxy(ThirdPartyYouTubeLib service) { this.service = service; } @Override public List<Video> listVideos() { if (cacheList == null) { cacheList = service.listVideos(); } return cacheList; } @Override public Video getVideoInfo(String id) { Video video = cacheVideo.get(id); if (video == null) { video = service.getVideoInfo(id); cacheVideo.put(id, video); } return video; } public File downloadVideo(String id) { File file = cacheFile.get(id); if (file == null) { file = service.downloadVideo(id); cacheFile.put(id, file); } return file; } }
Client
public class YouTubeManager { private ThirdPartyYouTubeLib service; public YouTubeManager(ThirdPartyYouTubeLib service) { this.service = service; } public void renderVideoPage(String id) { Video info = service.getVideoInfo(id); //... } public void renderListPanel() { List<Video> list = service.listVideos(); // ... } public void reactOnUserInput() { renderVideoPage(); renderListPanel(); } } public class Application { public static void main(String[] args) { ThirdPartyYouTubeLib proxy = new YouTubeCacheProxy(new ThirdPartyYouTubeClass()); YouTubeManager manager = new YouTubeManager(proxy); manager.reactOnUserInput(); } }
적용
- 가상 프록시(지연 초기화). 앱이 시작될 때 객체를 생성하는 대신, 객체 초기화가 실제로 필요한 시점까지 지연할 수 있다. 가끔 필요한 무거운 서비스 객체가 항상 가동되어 있어 시스템 자원들을 낭비하는 경우에 사용
- 보호 프록시(접근 제어). 특정 클라이언트들만 서비스 객체를 사용할 수 있도록 하려는 경우에 사용
- 원격 프록시. 서비스 객체가 원격 서버에 존재하는 경우 사용하며, 프록시는 네트워크를 통해 클라이언트 요청을 전달하여 네트워크와 관련된 복잡한 작업들을 처리한다.
- 로깅 프록시. 서비스 객체에 대한 요청들의 기록을 유지하려는 경우에 사용하며, 각 요청을 서비스에 전달하기 전에 로깅할 수 있다.
- 캐싱 프록시. 클라이언트 요청들의 결과들을 캐시하고 이 캐시들의 수명 주기를 관리해야할 때, 특히 결과들이 상당히 큰 경우에 사용한다. 항상 같은 결과를 생성하는 반복 요청들에 대해 캐싱을 구현할 수 있다.
- 스마트 참조. 서비스 객체 또는 그 결과에 대한 참조를 얻은 클라이언트들을 추적할 수 있다. 클라이언트들을 점검하여 클라이언트들이 활성화 상태인지 확인할 수 있으며, 클라이언트 리스트가 비어 있으면 해당 서비스 객체를 닫고 시스템 자원을 확보한다.
장단점
장점
- 클라이언트들이 알지 못하는 상태에서 서비스 객체를 제어할 수 있다.
- 클라이언트들이 신경 쓰지 않을 때 서비스 객체의 수명 주기를 관리할 수 있다.
- 프록시는 서비스 객체가 준비되지 않았거나 사용할 수 없는 경우에도 작동한다.
- 개방/폐쇄 원칙 : 서비스나 클라이언트들을 변경하지 않고도 새 프록시들을 도입할 수 있다.
단점
- 새로운 클래스들을 많이 도입해야 하므로 코드가 복잡해질 수 있다.
- 서비스의 응답이 늦어질 수 있다.
참고
'STUDY > 디자인패턴' 카테고리의 다른 글
Flyweight Pattern(플라이웨이트 패턴) (0) 2025.01.07 Facade Pattern(퍼사드 패턴) (0) 2025.01.07 Decorator Pattern(데코레이터 패턴) (0) 2024.12.25 Composite Pattern(복합체 패턴) (0) 2024.12.25 Bridge Pattern(브리지 패턴) (0) 2024.12.08