////
Search

11장 - 프록시 패턴

Created
2022/09/03 11:30
Tags
디자인패턴

프록시 패턴(Proxy Pattern)

프록시 패턴은 특정 객체로의 접근을 제어하는 대리인(특종 객체를 대변하는 객체)을 제공합니다.
프록시 패턴을 사용하면 원격 객체라던가 생성하기 힘든 객체, 보안이 중요한 객체와 같은 다른 객체로의 접근을 제어하는 대리인 객체를 만들 수 있다.
프록시에서 접근을 제어하는 방법
원격 프록시를 써서 원격 객체로의 접근을 제어할 수 있음
가상 프록시를 써서 생성하기 힘든 자원으로의 접근을 제어할 수 있음
보호 프록시를 써서 접근 권한이 필요한 자원의 접근을 제어할 수 있음
호출을 중간에서 가로챈다는게 중요하다.

원격 프록시

원격 프록시는 원격 객체의 로컬 대변자 역할을 하게 됩니다.
원격 객체란 다른 자바 가상머신의 힙에서 살고있는 객체를 뜻합니다.
로컬 대변자를 호출하면 다른 원격 객체에게 그 메소드를 호출을 전달해주는 객체를 뜻합니다.
결과적으로 클라이언트는 로컬 객체를 사용하는것처럼 행동할 수 있습니다.

원격 메소드의 호출 과정

1.
클라이언트 객체에서 특정 메소드를 사용
2.
메소드 명과 인자 값 등을 직렬화해서 네트워크로 원격 객체에 전달
3.
원격 객체는 로직을 수행
4.
결과를 다시 직렬화하여 프록시 객체에게 전달
5.
프록시 객체는 메소드가 완료된 것처럼 작동

가상 프록시

객체 생성하는데 많은 비뵹이 드는 객체를 대신합니다.

가상 프록시의 작동 과정

이미지를 불러오는 객체를 기준으로 했을 때
1.
이미지를 불러오는 객체를 가상 프록시로 만들어 이미지를 가져오는 메소드를 실행
a.
가상 프록시는 화면에 이미지를 가져오는 중이라는 메세지를 나타나게 함
2.
잠시 후 이미지 로딩이 완료되고, 실제 객체가 완성됨
3.
이미지 생성이 완료된 객체를 통해서 화면에 이미지를 노출 시킴

원격 프록시와 가상 프록시 비교

원격 프록시
원격 프록시는 다른 JVM에 들어있는 객체의 대리인에 해당하는 로컬 객체
프록시의 메소드를 호출하면 그 호출이 네트워크로 전달되어 결국 원격 객체의 메소드가 호출됨
그 결과는 다시 프록시를 거쳐서 클라이언트에게 전달됨
가상 프록시
가상 프록시는 생성하는 데 많은 비용이 드는 객체를 대신함
진짜 객체가 필요한 상황이 오기 전까지 객체의 생성을 미루는 기능을 제공
객체 생성 전이나 객체 생성 도중에 객체를 대신하기도하고, 생성이 끝나면 직접 요청을 전달 하기도함

데코레이터와 프록시의 차이점

사용 용도로 구분이 가능하다.
데코레이터는 클래스에 새로운 동작을 추가하는 용도로 사용된다.
프록시는 어떤 클래스로의 접근을 제어하는 용도로 사용된다.

어댑터와 프록시의 차이점

어댑터는 다른 객체의 인터페이스를 바꿔줍니다.
프록시는 동일한 인터페이스를 사용합니다.

보호 프록시

자바의 java.lang.reflect 패키지 안에 프록시 기능이 내장되어 있다.
지정한 클래스에 메소드 호출을 전달하는 프록시 클래스를 만들 수 있다.
진짜 프록시 클래스는 실행 중 생성되므로 이러한 자바 기술을 동적 프록시(dynamic proxy)라고 부른다.
특정 인터페이스 메소드 접근의 권한에 따라서 이용 가능 여부를 지정할 수 있다.

만들어보기

public interface Person { String getName(); String getGender(); String getInterests(); int getGeekRating(); void setName(String name); void setGender(String gender); void setInterests(String interests); void setGeekRating(int rating); }
Java
복사
import java.lang.reflect.*; public class OwnerInvocationHandler implements InvocationHandler { Person person; public OwnerInvocationHandler(Person person) { this.person = person; } public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException { try { if (method.getName().startsWith("get")) { return method.invoke(person, args); } else if (method.getName().equals("setGeekRating")) { throw new IllegalAccessException(); } else if (method.getName().startsWith("set")) { return method.invoke(person, args); } } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } }
Java
복사
Person getOwnerProxy(Person person) { return (Person) Proxy.newProxyInstance( person.getClass().getClassLoader(), person.getClass().getInterfaces(), new OwnerInvocationHandler(person)); }
Java
복사