Proxy
Proxy 는 단어 뜻대로 대리, 대리인이라는 뜻을 가지고 있습니다.
대리, 대리인은 누군가를 대신해서 그 역할을 수행하는 존재입니다. Proxy 패턴에서도 Proxy 라는 단어에 맞게
어떤 일을 수행할 때 대신 전달하거나 처리하는 역할을 합니다.
Proxy 패턴
출처 : https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9D%EC%8B%9C_%ED%8C%A8%ED%84%B4
위 Proxy 패턴 이미지를 보면은 DoAction() 메서드를 가지고 있는 Subject 라는 인터페이스가 존재합니다.
Subject 인터페이스를 구현하는 클래스는 RealSubject 와 Proxy 2개의 클래스입니다.
클라이언트가 Subject 인터페이스를 구현한 RealSubject 클래스의 DoAction() 메서드를 호출하면
Proxy 라는 클래스가 대신 RealSubject 의 DoAction() 메서드를 호출하고 반환값을 클라이언트에게 전달한다.
즉, 정리하면 아래와 같다.
1. DoAction() 메서드를 가지고 있는 Subject 인터페이스가 존재한다.
2. Subject 인터페이스를 구현한 클래스는 RealSubject 와 Proxy 가 있다.
3. 클라이언트는 RealSubject 클래스의 DoAction() 메서드를 호출한다.
4. 클라이언트의 요청을 Proxy 클래스가 대신해서 RealSubject 클래스의 DoAction() 을 호출한다.
5. 호출한 Proxy 클래스는 반환값을 받아 클라이언트에게 전달한다.
이렇게 꼭 Proxy 클래스가 존재해야 하는 이유는 RealSubject 클래스는 본연의 필수적인 역할만 수행하도록 하고
또 다른 역할을 부여하지 않는다. (단일 책임의 원칙, SRP)
단일 책임의 원칙(Single Responsibility Principle)
"어떤 클래스를 변경해야 하는 이유는 오직 하나 뿐이어야 한다." -로버트 C. 마틴
클래스에 역할과 책임을 너무 많이 주지 마라는 뜻이다.
어떤 특정 클래스에 모든 기능을 넣기 보다는 목적과 취지에 맞는 속성과 메서드를 잘 분리해서
여러 클래스에 넣어야 한다.
위키백과에 있는 자바 코드를 가져와서 살펴보자
import java.util.*;
interface Image {
public void displayImage();
}
//on System A
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}
private void loadImageFromDisk() {
System.out.println("Loading " + filename);
}
@Override
public void displayImage() {
System.out.println("Displaying " + filename);
}
}
//on System B
class ProxyImage implements Image {
private String filename;
private Image image;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void displayImage() {
if (image == null)
image = new RealImage(filename);
image.displayImage();
}
}
class ProxyExample {
public static void main(String[] args) {
Image image1 = new ProxyImage("HiRes_10MB_Photo1");
Image image2 = new ProxyImage("HiRes_10MB_Photo2");
image1.displayImage(); // loading necessary
image2.displayImage(); // loading necessary
}
}
Image 라는 인터페이스가 있고 해당 인터페이스를 구현한 RealImage 클래스와 ProxyIamge 클래스가 있다.
RealImage 클래스는 생성될 때 생성자 함수에 의해 filename 을 한번 출력하고 구현 메서드를 호출하면
또 한번 출력된다.
ProxyImage 클래스는 구현 메서드인 displayImage 에서 RealImage를 생성하고 RealImage 클래스의
구현메서드인 displayImage() 메서드를 호출한다.
이제 main 에서 ProxyImage 클래스를 2개 생성하고 호출하게 되면 아래와 같이 RealImage 클래스에서 호출한
filename 들이 출력된다.
//출력 결과
Loading HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Loading HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
위와 같이 RealImage 클래스는 filename 이라는 변수명만 출력하는 본연의 역할만 수행하고
ProxyImage 클래스는 클라이언트의 요청을 받아 파일명을 넘기면 대신해서 RealImage 를 호출하여
로직을 대신 수행하게 됩니다.