2011년 5월 23일 월요일

The Proxy Pattern


12. The Proxy Pattern
Proxy 패턴은 복잡하거나 생성하는 데 시간이 걸리는 객체를 좀더 간단한 객체로 나타내기 위해 사용되는 패턴이다. 객체를 생성하는 일이 자원 소모나 시간 소요라는 점에서 소비가 클 경우 Proxy 패턴은 개발자가 이런 객체를 실제로 필요로 할 때까지 해당 객체의 생성 작업을 늦춘다. Proxy 패턴은 단순 객체를 대상으로 하는 전체 객체로서 일반적으로 같은 메소드를 갖는다. Proxy 패턴은 객체의 인스턴스를 요청하는 작업과 해당 객체가 실제로 필요한 경우를 구별 하기 위해서도 사용될 수 있다. 예를 들어, 프로그램 초기화는 다수의 객체를 생성할 수 있지만, 생성된 객체가 모두 곧바로 사용되는 것은 아니다. 이런 경우 Proxy 패턴이 필요한 경우에만 실제 객체를 불러올 수 있다.
대용량 이미지 파일을 불러와서 출력해야 하는 프로그램의 경우를 생각해 보자. 해당 화면의 내용을 정확하게 설정하기 위해서 프로그램이 시작되면 선택된 이미지가 출력되고 있다고 표시해야 한다. 그러나 해당 이미지를 완전히 불러올 때까지는 실제 이미지의 출력을 연기할 수 있다. 이것은 특히 텍스트와 이미지가 혼합된 레이아웃을 제공하는 워드프로세서나 웹 브라우저와 같은 프로그램에서 중요한 기능이다.
이미지 프록시는 해당 이미지의 규모를 표현하기 위해 단순한 직사각형 및 다른 기호를 표시하는 동안 특정 이미지를 주목한 후 배경으로 해당 이미지를 불러올 수 있다.
Proxy 패턴은 해당 이미지에 대한 페인트 작업 요청을 받을 때까지 이미지를 늦게 불러올 수 있으며, 그런 다음에야 불러오기 작업을 시작할 수 있다.
정리하여 말하면 Proxy 패턴은 “어떤 오브젝트에 대한 접근을 제어해야할 때 그 오브젝트가 실제로 사용될 필요가 있을 때까지 생성과 초기화에 들어가는 총비용의 지출을 지연시키는 것이다”.
구조
*


역할
  • Proxy : 실제 오브젝트에 접근할 수 있도록 레퍼런스를 유지한다. Subject와 RealSubject의 인터페이스가 같다면 Subject 타입에 대한 레퍼런스로 정의할 수도 있다. 실제 Subject 오브젝트를 대신할 수 있도록 Subject와 동일한 인터페이스를 제공한다. 실제 오브젝트에 대한 접근을 조절하고, 생성/삭제를 책임질 수도 있다. Proxy의 종류에 따라 다음에 나열된 기능을 책임지기도 한다.

· Remote proxy는 원격지에 있는 실제 오브젝트에게 인코딩된 request를 보내기 위해 request와 argument를 인코딩한다.
· Virtual proxy는 실제 오브젝트에 대한 추가정보를 캐싱함으로써 실제 오브젝트에 대한 접근을 지연시킬 수 있다. 예를 들어, ImageProxy는 실제 이미지의 extent를 캐싱한다.
· Protection proxy는 caller가 request를 수행하는데에 필요한 권한을 가지고 있는지 검사한다.
  • Subject : Proxy가 Real Subject를 완전히 대체할 수 있도록 그들의 공통된 인터페이스를 정의한다.
  • Real Subject : Proxy가 표현할 실제 오브젝트를 정의한다.

의도
어떤 오브젝트에 대한 접근을 제어하기 위해 그 오브젝트를 대신할 다른 오브젝트를 제공한다.
적용시기
1 대용량의 이미지 파일과 같은 객체가 불러오는 데 시간이 오래 걸릴 경우.(Virtual proxy)
2 해당 객체가 원격 제어 컴퓨터에 존재하고, 네트워크를 통해 해당 객체를 불러오는 작업이 피크 타임에서 특히 느리게 수행될 경우(Remote proxy)
3 해당 객체가 제한된 접근권을 가질 경우, Proxy 패턴이 해당 사용자에 대한 접근 권한을 유요화 한다.(Protection proxy)
결론
Proxy 패턴은 오브젝트에 접근하는 우회적인 단계를 제공한다. 이 우회적인 접근은 Proxy의 종류에 따라 여러 용도를 가진다.
  • Remote proxy는 실제 오브젝트가 원격지에 있다는 사실을 숨길 수 있다.
  • Virtual proxy는 실제 오브젝트를 on-deman 방식으로 생성함으로써 최적화를 수행할 수 있다.
  • Protection proxy나 Smart reference는 실제 오브젝트에 접근하기 전에 추가적인 관리기능을 수행할 수 있다.

Proxy가 클라이언트는 모르게 수행할 수 있는 다른 최적화가 있다. Copy-on-write라고 불리는 기법으로, on-demand 생성과 연관된다. 크고 복잡한 오브젝트를 복사하는 것은 비싼 오퍼레이션이 될 수 있다. 만약 복사본이 변경되지 않는다면 이와 같은 cost를 지불할 필요가 전혀 없다. Proxy가 복사 수행을 지연시킴으로써 복사본이 변경될 때만 실제로 오브젝트를 복사하는 비용을 지불하는 것을 보장할 수 있다.
Copy-on-write 기법
subject(실제 오브젝트)에 대한 레퍼런스를 카운트하고 있어야 한다. Proxy를 복사하는 것은 단순히 레퍼런스 카운트를 하나 증가시킬뿐 실제로 subject를 복사하지는 않는다. 그리고 클라이언트가 복사본 Proxy를 통해 subject를 수정하려고 할 때에만 실제로 subject를 복사한다. 이 때에는 proxy가 subject의 레퍼런스 카운트를 감소시켜야 한다.
Copy-on-write 기법은 큰 오브젝트를 복사하는데 소요되는 cost를 현저하게 줄여준다.


예제소스
*


예제 소스
import java.awt.*;
import java.awt.event.*;
import java.util.*;
//swing classes
import javax.swing.text.*;
import javax.swing.*;
import javax.swing.event.*;
public class JxFrame extends JFrame {
public JxFrame(String title) {
super(title);
setCloseClick();
setLF();
}
private void setCloseClick() {
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
);
}
private void setLF() {
String laf = UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel(laf);
} catch (UnsupportedLookAndFeelException exc) {
System.err.println("Warning: UnsupportedLookAndFeel: " + laf);
} catch (Exception exc) {
System.err.println("Error loading " + laf + ": " + exc);
}
}
}
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.border.*;
import java.awt.*;
public class ImageProxy extends JPanel implements Runnable {
private int height, width;
private MediaTracker tracker;
private Image img;
private JFrame frame;
private Thread imageCheck;
public ImageProxy(String filename, int w, int h) {
height = h;
width = w;
tracker = new MediaTracker(this);
img = Toolkit.getDefaultToolkit().getImage(filename);
tracker.addImage(img, 0);
imageCheck = new Thread(this);
imageCheck.start();
try {
tracker.waitForID(0,1);
} catch (InterruptedException e) {
}
}
public void paint(Graphics g) {
if (tracker.checkID(0)) {
height = img.getHeight(frame);
width = img.getWidth(frame);
g.setColor(Color.lightGray);
g.fillRect(0,0, width, height);
g.drawImage(img, 0, 0, this);
} else {
g.setColor(Color.black);
g.drawRect(1, 1, width-2, height-2);
}
}
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void run() {
try {
Thread.sleep(1000);
while (! tracker.checkID(0))
Thread.sleep(1000);
} catch (Exception e) {
}
repaint();
}
}
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.border.*;
import java.awt.*;
public class ProxyDisplay extends JxFrame {
public ProxyDisplay() {
super("Proxy 테스트");
JPanel p = new JPanel();
getContentPane().add(p);
p.setLayout(new BorderLayout());
ImageProxy image = new ImageProxy("mong.jpg", 321, 271);
p.add("Center", image);
p.add("North", new Label(" "));
p.add("West", new Label(" "));
setSize(580, 471);
setVisible(true);
}
static public void main(String[] argv) {
new ProxyDisplay();
}
}


관련패턴
  • Adapter : Adapter는 adaption의 대상이 되는 오브젝트와는 다른 인터페이스를 제공한다. 반대로 proxy는 subject와 동일한 인터페이스를 제공한다. 그러나, 실제로는 protection proxy 등의 경우 조건에 따라서 subject로 requset를 전달하지 않고 거부해 버리기 때문에, subject의 인터페이스에 대한 부분집합을 제공한다고 볼 수도 있다.
  • Decorator : Decorator와 proxy는 비슷한 모습으로 구현이 되기는 하지만, 목적은 전혀 다르다. Decorator는 특정 오브젝트에 별도의 기능을 추가하는 역할을 하지만, proxy는 오브젝트에 대한 접근 자체를 제어한다. Proxy의 종류에 따라 얼마나 decorator와 비슷하게 구현될 것인가가 달라진다. Protection proxy의 구현은 decorator와 거의 동일하다. 반면에 remote proxy의 경우 실제 subject에 대한 직접적인 레퍼런스가 아닌 "host ID, local address" 식의 간접적인 레퍼런스만을 가지고 있다. Virtual proxy의 경우 처음에는 간접적인 레퍼런스만 가지고 있지만 결국에는 직접적인 레퍼런스를 만들어 사용하게 된다.

    댓글 없음:

    댓글 쓰기

    ETL 솔루션 환경

    ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...