클라이언트가 요청한 결과를 서버에 직접요청 하는 것이 아니라 어떤 대리자를 통해서 대신 간접적으로 서버에 요청할 수 있는데, 여기서 대리자가 프록시(Proxy) 이다.
클라이언트는 프록시에게 요청을 한것인지, 서버에게 요청을 한것인지 몰라야 한다. 때문에 서버와 프록시는 같은 인터페이스를 사용하며, 클라이언트가 사용하는 서버 객체를 프록시 객체로 변경해도 클라이언트 코드를 변경하지 않고도 동작이 가능해야 한다.
즉, 클라이언트와 서버의 의존관계를 변경해도 클라이언트 코드를 변경하지 않아도 된다는 것이다.
프록시의 기능
GOF 디자인 패턴에서 프록시 패턴의 주요 목적은 접근 제어이다.
GoF의 디자인 패턴은 소프트웨어 공학에서 가장 많이 사용되는 디자인 패턴이다.
목적에 따라 분류하면 생성, 구조, 행동 3가지로 나눌 수 있으며, 범위에 따라 분류하면 클래스, 객체가 있다.
Proxy 설명에 이어서 프록시 패턴은 객체에 대한 접근을 제어하는 용도로 대리인에 해당하는 객체를 제공하는 패턴이다.
RealSubject의 객체의 생성비용이 많이 들어 실제 사용 시점에 객체를 생성하거나, 실제 객체의 접근을 제한 및 제어를 해야 할때 드물게 쓰인다.
Proxy 와 RealSubject 는 같은 인터페이스를 구현하기에 RealSubject 객체가 들어갈 자리면 어디든 Proxy 가 들어갈 수 있으며, Proxy 를 통해서 RealSubject와 데이터를 주고 받는다.
public class MyProgram {
public static void main(String[] args) {
ArrayList<Thumbnail> thumbnails = new ArrayList<Thumbnail>();
thumbnails.add(new ProxyThumbnail("Git 강좌", "/git.mp4"));
thumbnails.add(new ProxyThumbnail("Rest API란?", "/rest-api.mp4"));
for (Thumbnail thumbnail : thumbnails) {
thumbnail.showTitle();
}
// 제목:Git 강좌
// 제목:Rest API란?
thumbnails.get(2).showPreview();
thumbnails.get(2).showPreview();
// /docker.mp4로부터 도커 사용법의 영상 데이터 다운
// 도커 사용법의 프리뷰 재생
// 도커 사용법의 프리뷰 재생
}
}
###############################################
interface Thumbnail {
public void showTitle ();
public void showPreview ();
}
class RealThumbnail implements Thumbnail {
private String title;
private String movieUrl;
public RealThumbnail (String _title, String _movieUrl) {
title = _title;
movieUrl = _movieUrl;
}
public void showTitle () {
System.out.println("제목:" + title);
}
public void showPreview () {
System.out.println(title + "의 프리뷰 재생");
}
}
class ProxyThumbnail implements Thumbnail {
private String title;
private String movieUrl;
private RealThumbnail realThumbnail;
public ProxyThumbnail (String _title, String _movieUrl) {
title = _title;
movieUrl = _movieUrl;
}
public void showTitle () {
System.out.println("제목:" + title);
}
public void showPreview () {
if (realThumbnail == null) {
realThumbnail = new RealThumbnail(title, movieUrl);
}
realThumbnail.showPreview();
}
}
코드를 살펴보면 ProxyThumbnail, RealThumbnail 클래스 모두 Thumbnaild 인터페이스를 상속받는다. ProxyThumbnail 클래스에서도 RealThumbnail 객체가 있지만 생성자는 존재하지 않는다. 또한 showPreview () 함수에서 realThumbnail 값이 최조에 null 이기에 RealThumbnail 의 객체를 생성하고 RealThumbnail 의 showPreview() 함수를 호출한다.
즉 ProxyThumbnail는 필요한 요청이 있을때에만 객체를 생성하기에 가볍다고 성능이 효율적이라고 볼 수 있다.
Facade 는 어떠한 커다란 코드 부분에 대하여 간략화된 인터페이스를 제공해주는 디자인 패턴이다. 패턴이란 인식 없이 널리 사용되며, 단순한 패턴이라고 볼 수 있다.
퍼사드 객체는 바깥쪽의 코드가 라이브러리의 안쪽 코드에 의존하는 일을 감소시켜며, 복잡한 소프트웨어를 사용 가능하게 하는 인터페이스를 제공해 준다.
public class FacadePattern {
public static void main(String[] args) {
...
new MyLocFacade().printMyAddress();
}
}
########################################
public class MyLocFacade {
public void printMyAddress () {
double[] myGeoLoc = new GeoLocation().getGeoLoc();
InternetConnection conn = new InternetConnection();
conn.connect();
String data = conn.getData("https://주소_API_URL", myGeoLoc);
conn.disconnect();
Map<String, Object> address = new Json().parse(data);
System.out.println(address.get("address"));
}
}
코드를 간단히 살펴보면 main method 에서 new MyLocFacade().printMyAddress(); 부분에서 MyLocFacade 클래스의 printMyAddress() 함수 호출로 인해 main method 의 부담을 덜어주는걸 확인할 수 있다.
템플릿 메서드도 어렵지 않은 패턴으로 어떤 작업을 처리하는 일부분을 서브클래스로 캡슐화해 전체일을 수행하는 구조는 바꾸지 않으면서 특정 단계에서 수행하는 내역을 바꾸는 패턴이다.
전체적으로는 동일하나 부분적으로는 다른 구문으로 구성된 메서드의 코드 중복을 최 소화 하기 위함이다.
AbstractClass : 템플릿 메서드를 정의하는 클래스
ConcreteClass : 물려받은 primitive 메서느, hook 메서드를 구현하는 클래스
public abstract class MapView {
protected abstract void connectMapServer();
protected abstract void showMapOnScreen();
protected abstract void moveToCurrentLocation();
public void initMap () {
connectMapServer();
showMapOnScreen();
moveToCurrentLocation();
}
}
#######################################################
public class NaverMapView extends MapView {
@Override
protected void connectMapServer() {
System.out.println("네이버 지도 서버에 연결");
};
@Override
protected void showMapOnScreen() {
System.out.println("네이버 지도를 보여줌");
};
@Override
protected void moveToCurrentLocation() {
System.out.println("네이버 지도에서 현 좌표로 이동");
};
}
코드를 살펴보면 MapView 는 추상 클래스로 선언되어 initMap() 메서드를 구성하며 NaverMapView 클래스는 MapView 추상클래스를 상속하며 MapView 추상클래스의 메서드들을 구체화하여 기능을 구현하는 것을 볼 수 있다.
자세히 보면 자식 클래스에서 함수들이 Override 되어있는 것 또한 볼 수 있다.
https://www.youtube.com/watch?v=q3_WXP9pPUQ&t=1s
https://www.youtube.com/watch?v=lJES5TQTTWE&t=317s
김영한 스프링 핵심 원리 - 고급편