What is 프록시 패턴?
- 프록시 패턴은 다른 무언가와 이어지는 인터페이스의 역할을 하는 패턴입니다
한마디로 무언가를 대신해주는 대리자 입니다
또 너무나 어렵죠?
본래는 Proxy라는 객체가 해야될 일을 RealSubject 객체에게 의존성 주입(합성) 시킴으로써
메서드(메시지) 실행에 대한 책임을 RealSubject에게 넘기는 방식입니다
그렇게 되면 Proxy라는 객체는 외부에게 메서드를 노출하지 않고, 해당 로직대로 흐름을 제어할 수 있습니다
Why 프록시?
왜 쓸까요?
왜 굳이 숨길까요?
왜 합성시킴으로써 다른 사람에게 위임하는 걸까요?
프록시 패턴은 실제 세계와 아주 밀접하게 연관되어 있습니다
우리가 흔히 가게에서 결제하는 체크카드를 예로 들어볼까요?
체크카드로 결제를 하게 되면, 체크카드에서 돈이 빠져나가나요?
아닙니다
체크카드(Proxy)로 결제를 하게 되면, 체크카드(Proxy)에 연관(합성)되어 있는 계좌(RealSubject)에 돈이 빠져나가게 됩니다
체크카드는 순전히 결제를 대행해주는 Proxy 역할을 하고, 은행계좌(RealSubject)는 외부로부터 숨길 수 있게 되죠
그렇기 때문에 프록시 패턴을 사용하는 겁니다 ^-^
은행계좌라는 민감정보(Sensitive Data)를 외부에 노출시킬 수는 없으니까요~
How to 프록시
그렇다면 이번에는 예시를 통해 실제로 구현해보겠습니다
저는 인터넷을 예로 들어볼게요
인터넷 도메인(www.xxxxx.com)에 접속하고 싶은데, 유해사이트에 대한 접속은 차단하고 싶어요
그렇다면 이것은 프록시를 통해서 유해사이트를 필터링해서 접속할 수 있게 기능을 구현하겠습니다!
먼저, 인터넷이라는 인터페이스를 만들어볼게요!
package designpattern.proxy;
interface Internet {
String connectTo(String serverHost);
}
1. Internet 인터페이스
간단하게 접속하기 위한 Reqeust에 대한 응답을 Response로 받는 객체입니다!
package designpattern.proxy;
public class RealInternet implements Internet {
@Override
public String connectTo(final String serverHost) {
return "Connecting to " + serverHost;
}
}
2. RealInternet 객체
실제로 모든 도메인은 다 접속할 수 있습니다
그러니 실제 인터넷이라는 객체는 조건없이 접속할 수 있죠!
package designpattern.proxy;
import com.google.common.collect.Lists;
import java.util.List;
public class ProxyInternet implements Internet {
private static List<String> bannedSite = Lists.newArrayList("abc.com", "def.com", "ijk.com");
private Internet internet = new RealInternet();
@Override
public String connectTo(final String serverHost) {
if (bannedSite.contains(serverHost.toLowerCase())) {
throw new IllegalArgumentException(String.format("해당하는 호스트는 접근이 불가능합니다 : %s", serverHost));
}
return internet.connectTo(serverHost);
}
}
3. ProxyInternet 객체
들어갈 수 없는 도메인은 막고, 프록시를 통해서 Internet에 접속하기 위한 객체입니다!
이 ProxyInternet을 보시면 아시겠지만, 실제 인터넷에 대한 접속은 RealInternet객체가 책임을 맡고 있어요
그렇기 때문에 ProxyInternet은 접속에 대한 차단의 책임을 가지게 되는 것이죠
이는 SRP(Single Responsibility Principle)을 준수한 객체지향적인 코드입니다!
그러면 테스트하러 가볼까요?
package designpattern.proxy;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
class ProxyInternetTest {
private Internet internet;
@BeforeEach
void setUp() {
internet = new ProxyInternet();
}
@Test
@DisplayName("도메인이 올바르게 연결되는지 테스트")
void proxy_internet_connecting_test() {
/* Then */
assertThat(internet.connectTo("naver.com")).isEqualTo("Connecting to naver.com");
}
@Test
@DisplayName("접근금지인 도메인은 예외를 던지는지 테스트")
void proxy_internet_ban_test() {
/* Then */
assertThrows(IllegalArgumentException.class, () -> internet.connectTo("abc.com"));
}
}
테스트 결과를 보시면~?
테스트가 말끔히 통과되네요 ㅎㅎ
마지막으로 Class Diagram을 보시면서 마무리할게요!
프록시 장단점
장점
- 외부로부터 숨기기 때문에 Proxy패턴은 Security합니다
- 실제 데이터에 대한 객체는 하나의 객체(RealSubject)이기 때문에 메모리 및 성능을 아낄 수 있습니다
단점
- 시스템이 거대해질 수록, 일부는 Proxy에 직접 접근하고, 일부는 RealSubject에 직접 접근하는 이질적인 설계를 초래할 수 있습니다
참고
GeeksforGeeks - Proxy Pattern
'Developer > Design Pattern' 카테고리의 다른 글
Template Callback Pattern - 템플릿 콜백 패턴 (0) | 2020.02.23 |
---|---|
Decorator Pattern - 데코레이터 패턴 (2) | 2020.01.26 |
Bridge Pattern - 브릿지 패턴 (0) | 2020.01.05 |
Composite Pattern - 컴포지트 패턴 (0) | 2019.11.06 |
Command Pattern - 커맨드 패턴 (2) | 2019.10.19 |