사용하고자 하는 객체에 직접 접근하는 것이 아닌,
대리자를 통하여 참조하는 것을 의미 한다.
주로 , 접근제어의 목적으로 사용 된다.
사진 : 위키백과
//인터페이스
public interface Subject{
void doAction();
}
//구체클래스
@Slf4j
public class RealSubject implements Subject{
@Override
public void doAction(){
log.info("Concrete doAction 실행");
}
}
//Client
public class Client{
private Subject subject;
public Client(Subject subject){
this.subject= subject;
}
}
해당 코드를 클라이언트에서 호출한다고 해보자.
//생성 및 호출
RealSubject sub1 = new RealSubject();
Client client = new Client(sub1);
client.subject.doAction();
//출력 결과
Concrete doAction 실행
코드를 수정하거나 추가하고 싶을 경우 ,
RealSubject의 doAction 메소드를 수정하면 된다.
여기서 만일 사용자에 따라 접근에 대한 권한을 부여하고 싶다고 가정해보자.
(Admin , NomarlUser)
Admin만 핵심로직을 실행할 수 있을 경우 아래처럼 바꿀 수 있다.
//인터페이스
public interface Subject{
void doAction(String grade);
}
@Slf4j
public class RealSubject implements Subject{
@Override
public void doAction(String grade){
if(grade.equals("Admin"){
log.info("Concrete doAction 실행");
}
}
}
변경이 필요할 경우 , 직접 클래스의 내용을 변경해야 한다.(심지어 현재의 경우 인터페이스까지 수정을 했다)
사용자에 대한 접근의 권한을 파악하는 로직도 함께 작성되어 있다.
지금이야 간단하지만 , 실제의 접근 권한을 확인하는 로직은 훨씬 복잡할 것이다.
그런 방대한 양의 코드가 한곳에 몰려 있으면 , 가독성 또한 좋지 못할 것이다.
또 접근 권한과 핵심 로직 둘 중에 하나의 기능에서라도 수정이나 확장이 발생을 고려하게 된다면 , 매번 해당 클래스를 수정해야 한다.
그럼 프록시를 도입해보자.
//인터페이스
public interface Subject{
void doAction();
}
//프록시
public class ProxySubject implements Subject{
private Subject subject;
private String grade;
public ProxySubject(Subject subject , String grade){
this.subject = subject;
this.grade = grade;
}
@Override
public void doAction(){
if(grade.equals("Admin"){
subject.doAction();
}
}
}
//구체
@Slf4j
public class RealSubject implements Subject{
@Override
public void doAction(){
log.info("Concrete doAction 실행");
}
}
내부에 구체클래스를 호출할 수 있게 참조하고 있다.
또한, 인터페이스와 구체클래스는 수정없이 그대로 두고
접근 권한 확인로직을 추가하였다.
프록시를 도입하여 책임을 분리 시킴으로써 , 훨씬 확장과 수정에 유리하게 바꾸었다.
//생성및 호출
RealSubject sub1 = new RealSubject();
ProxySubject sub2 = new ProxySubject(sub1);
Client client = new Client(sub2);
client.subject.doAction("Admin");
//결과
-사전 작업을 위한 빈번한 객체 생성이 필요할 경우 성능이 저하될 수 있다.
-동기성 문제등의 기능을 고려하여 작업이 필요할 경우 성능이 저하될 수 있다.
프록시 패턴은 사용목적에 따라 3가지로 분류할 수 있다.
필요로 하는 시점까지 객체의 생성을 연기 하고 , 해당 객체가 생성된 것처럼 동작하도록 만들고 싶을때 사용하는 패턴이라고 한다.
프록시에서 간단한 기능들은 처리하도록 한다.
그리고 많은 작업량을 요구하는 리소스의 경우 , 본 객체를 사용하도록 구현할 때 이용한다.
원격객체에 대한 대변자 역할을 하는 객체 서로다른 주소 공간에 있는 객체에 대해 마치 같은 주소 공간에 있는 것처럼 동작하게 만드는 패턴이라고 한다.
Google Docs를 예시로 들 수 있다.
브라우저는 브라우저대로 필요한 자원을 로컬에 가지고 있고 또다른 자원은 Google 서버에 있는 형태이다.
위의 예시처럼 구체 클래스에 대한 접근을 제어하기 위한 경우 사용하는 방식을 의미한다.
참고 :
https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9D%EC%8B%9C_%ED%8C%A8%ED%84%B4
https://coding-factory.tistory.com/711