반응형
디자인패턴
[Java][디자인 패턴] 13. 프록시 패턴 (Proxy Pattern)
객체 접근을 제어하기 위해 중간 단계에 대리자를 위치시키는 패턴이다.
프록시 패턴이란?
- 프록시는 실제 객체를 호출하면 행위를 중간에 가로채서 다른 동작을 수행하는 객체로 변경한다.
- 객체를 정교하게 제어해야 하거나 객체 참조가 필요한 경우 프록시 패턴을 사용한다.
- 프록시 패턴의 적용 사례는 매우 다양하고 다른 패턴과 결합하여 사용되는 경우도 많다
- 프록시 패턴의 특징은 투명성을 이용해 객체를 분리하여 재위임한다는 것이다.
- 분리된 객체를 위임함으로써 대리 작업을 중간 단계에 삽입할 수도 있으며 분리된 객체를 동적으로 연결함으로써 객체의 실행 시점을 관리할 수도 있다.
- 프록시 패턴은 세밀한 객체의 접근이 필요할 때도 매우 유용하다.
프록시 패턴의 종류
- 원격 프록시
- 프록시 패턴을 가장 많이 응용하는 사레로 주로 데이터의 전달을 목적으로 사용
- 가상 프록시
- 프로그램의 실행 속도를 개선하기 위한 패턴
- 프록시 패턴을 이용해서 무거운 객체 생성을 유보한다.
- 보호 프록시
- 통제 제어 목적으로 사용하는 프록시
- 객체 접근 제어를 위해 객체의 대리자 혹은 표시자를 제공한다.
- 스마트 참조자 프록시
- 실제 객체에 접근할 때 추가 행위를 부여하여 호출한다.
- 장식자 패턴과 유사하게 객체를 동적으로 확장할 때 응용한다.
- 방화벽, 레퍼런스, 동기화 등등
프록시 패턴 구조
책에 있는 예시 코드가 이해하기 쉬운 듯하여 이 예제는 직접 짜지 않고 책에 있는 PHP 코드를 Java 코드로 변경하여 구현했다.
프록시 패턴 코드
1. 각 행동에 대한 인증 enum 클래스
public enum Permit {
ACTION1, ACTION2;
}
2. Subject 인터페이스 (프록시와 실제 객체가 사용할 수 있는 메서드를 정의)
public interface Subject {
String action1();
String action2();
boolean isProxy();
}
3. RealSubject 클래스 (Subject를 구현한 진짜 행동을 하는 클래스)
public class RealSubject implements Subject {
public RealSubject() {
System.out.println(this.getClass().getName() + " 객체 생성");
}
public String action1() {
System.out.println(this.getClass().getName() + ": action1");
return (this.getClass().getSimpleName() + ": action1");
}
public String action2() {
System.out.println(this.getClass().getName() + ": action2");
return (this.getClass().getSimpleName() + ": action2");
}
@Override
public boolean isProxy() {
return false;
}
}
4. Proxy 클래스 (Subject를 구현한 프록시 클래스)
public class Proxy implements Subject {
private Subject subject;
private Permit permit;
public int getAction1Count() {
return action1Count;
}
private int action1Count;
public Proxy(Permit permit) {
System.out.println(this.getClass().getName() + " 객체 생성(레이지 로딩)");
this.permit = permit;
this.action1Count = 0;
}
public Proxy(Subject subject) {
System.out.println(this.getClass().getName() + " 객체 생성");
this.subject = subject;
}
@Override
public String action1() {
System.out.println(this.getClass().getName() + ": action1");
action1Count++;
return "프록시로 action1 메서드 대체";
}
@Override
public String action2() {
System.out.println(this.getClass().getName() + ": action1");
if (Permit.ACTION2 != this.permit) {
return "action2 의 실행 권한이 없습니다.";
}
if (this.subject == null) {
this.real();
}
return this.subject.action2();
}
private void real() {
this.subject = new RealSubject();
}
public boolean isProxy() {
return true;
}
}
5. 프록시 팩토리 클래스
public class ProxyFactory {
public Subject getObject() {
return new Proxy(new RealSubject());
}
}
6. Real Subject 테스트 코드
class RealSubjectTest {
@Test
@DisplayName("RealSubject 바로 호출하기")
void action() {
RealSubject realSubject = new RealSubject();
realSubject.action1();
realSubject.action2();
}
}
결과
design.pattern.ch13.proxy.basic.RealSubject 객체 생성
design.pattern.ch13.proxy.basic.RealSubject: action1
design.pattern.ch13.proxy.basic.RealSubject: action2
6.Proxy 테스트 코드
class ProxyTest {
@Test
@DisplayName("프록시 객체 테스트")
void action() {
ProxyFactory proxyFactory = new ProxyFactory();
Subject subject = proxyFactory.getObject();
subject.action1();
subject.action2();
}
@Test
@DisplayName("프록시 레이지로딩 테스트 (ACTION1 권한)")
void actionLazyLoadingPermit1() {
Proxy proxy = new Proxy(Permit.ACTION1);
assertEquals("프록시로 action1 메서드 대체", proxy.action1());
assertEquals("action2 의 실행 권한이 없습니다.", proxy.action2());
}
@Test
@DisplayName("프록시 레이지로딩 테스트 (ACTION2 권한)")
void actionLazyLoadingPermit2() {
Proxy proxy = new Proxy(Permit.ACTION2);
assertEquals("프록시로 action1 메서드 대체", proxy.action1());
assertEquals("RealSubject: action2", proxy.action2());
}
@Test
@DisplayName("프록시의 action1 카운트 수 구하기")
void actionProxyCount() {
Proxy proxy = new Proxy(Permit.ACTION1);
proxy.action1();
proxy.action1();
proxy.action1();
proxy.action1();
assertEquals(4, proxy.getAction1Count());
}
}
# 프록시 객체 테스트 결과
design.pattern.ch13.proxy.basic.RealSubject 객체 생성
design.pattern.ch13.proxy.basic.Proxy 객체 생성
design.pattern.ch13.proxy.basic.Proxy: action1
design.pattern.ch13.proxy.basic.Proxy: action1
# 프록시 레이지 로징 테스트 (Action1 권한)
design.pattern.ch13.proxy.basic.Proxy 객체 생성(레이지 로딩)
design.pattern.ch13.proxy.basic.Proxy: action1
design.pattern.ch13.proxy.basic.Proxy: action1
# 프록시 레이지 로딩 테스트 (Action2 권한)
design.pattern.ch13.proxy.basic.Proxy 객체 생성(레이지 로딩)
design.pattern.ch13.proxy.basic.Proxy: action1
design.pattern.ch13.proxy.basic.Proxy: action1
design.pattern.ch13.proxy.basic.RealSubject 객체 생성
design.pattern.ch13.proxy.basic.RealSubject: action2
# 프록시 action1 카운트 수 구하기
design.pattern.ch13.proxy.basic.Proxy 객체 생성(레이지 로딩)
design.pattern.ch13.proxy.basic.Proxy: action1
design.pattern.ch13.proxy.basic.Proxy: action1
design.pattern.ch13.proxy.basic.Proxy: action1
design.pattern.ch13.proxy.basic.Proxy: action1
Github 코드
참고 자료
1.쉽게 바로 써먹는 디자인 패턴 책
http://www.yes24.com/Product/Goods/93173296
반응형
'개발 > 디자인패턴' 카테고리의 다른 글
[Java][디자인 패턴] 15. 명령 패턴 (Command Pattern) (0) | 2022.03.19 |
---|---|
[Java][디자인 패턴] 14. 반복자 패턴 (Iterator Pattern) (0) | 2022.03.18 |
[Java][디자인 패턴] 12. 플라이웨이트 패턴 (Flyweight Patten) (0) | 2022.03.16 |
[Java][디자인 패턴] 11. 파사드 패턴 (Facade Pattern) (0) | 2022.03.12 |
[Java][디자인 패턴] 10. 장식자 패턴 (Decorator Pattern) (0) | 2022.03.09 |