Writing /volume1/Web/Public/dokuwiki/data/log/deprecated/2024-11-15.log failed

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
study:java:design_pattern:proxy [2008/10/13 14:28] bananastudy:java:design_pattern:proxy [2021/05/12 00:27] (現在) – [ImageProxy Class] banana
行 2: 行 2:
 원격 프록시(Remote Proxy)는 일반적인 프록시 패턴(Proxy Pattern)을 구현하는 방법 가운데 하나입니다. 원격 프록시(Remote Proxy)는 일반적인 프록시 패턴(Proxy Pattern)을 구현하는 방법 가운데 하나입니다.
 이 외에도 몇 가지 변형된 방법이 있는데, 잠시 후에 알아보도록 하겠습니다. 일단 지금은 일반 프록시 패턴 이 외에도 몇 가지 변형된 방법이 있는데, 잠시 후에 알아보도록 하겠습니다. 일단 지금은 일반 프록시 패턴
-에 대해서 살보도록 하겠습니다.+에 대해서 살보도록 하겠습니다.
  
 프록시 패턴은 다음과 같이 정의됩니다. 프록시 패턴은 다음과 같이 정의됩니다.
行 23: 行 23:
  
 프록시 패턴의 정의에 대해서는 이 정도면 된 것 같으니까 클래스 다이어그램을 살펴볼까요? 프록시 패턴의 정의에 대해서는 이 정도면 된 것 같으니까 클래스 다이어그램을 살펴볼까요?
 +
 +
 +
 +
  
 ===== Class Diagram ===== ===== Class Diagram =====
行 28: 行 32:
  
 **다이어그램을 훑어볼까요?** **다이어그램을 훑어볼까요?**
-우선 RealSubject와 Proxy의 인터페이스를 제공하는 Subject 인터페이스가 있습니다. + 
-두 객체에서 똑같은 인터페이스를 구현하기 때문에 RealSubject가 들어가야 할 자리에+우선 %%RealSubject%%와 Proxy의 인터페이스를 제공하는 Subject 인터페이스가 있습니다. 
 +두 객체에서 똑같은 인터페이스를 구현하기 때문에 %%RealSubject%%가 들어가야 할 자리에
 Proxy를 대신 집어넣을 수 있습니다. Proxy를 대신 집어넣을 수 있습니다.
  
-실제 작업은 RealSubject 객체에서 처리됩니다. Proxy는 이 객체의 대변인 역할을 하면서+실제 작업은 **%%RealSubject%%** 객체에서 처리됩니다. **Proxy**는 이 객체의 대변인 역할을 하면서
 이 객체에 대한 접근을 제어하죠. 이 객체에 대한 접근을 제어하죠.
  
-Proxy에는 RealSubject에 대한 레퍼런스가 들어있습니다. Proxy에서 RealSubject를 생성하거나 +**Proxy**에는 **%%RealSubject%%**에 대한 레퍼런스가 들어있습니다. **Proxy**에서 **%%RealSubject%%**를 생성하거나 
-제거하는 역할을 책임지는 경우도 있습니다.클라이언트는 항상 Proxy를 통해서 RealSubject하고 데이터를 +제거하는 역할을 책임지는 경우도 있습니다.클라이언트는 항상 **Proxy**를 통해서 **%%RealSubject%%**하고 데이터를 
-주고 받습니다. Proxy와 RealSubject는 똑같은 인터페이스(Subject)를 구현하기 때문에 RealSubject +주고 받습니다. **Proxy**와 **%%RealSubject%%**는 똑같은 인터페이스(Subject)를 구현하기 때문에 **%%RealSubject%%** 
- 객체가 들어갈 자리라면 어디든지 Proxy를 대신 집어넣을 수 있습니다. Proxy는 RealSubject에 대한 + 객체가 들어갈 자리라면 어디든지 **Proxy**를 대신 집어넣을 수 있습니다. **Proxy**는 **%%RealSubject%%**에 대한 
-접근을 제어하는 역할도 맡게 됩니다. RealSubject가 원격 시스템에서 돌아가거나, 그 객체를 생성하는 데 +접근을 제어하는 역할도 맡게 됩니다. **%%RealSubject%%**가 원격 시스템에서 돌아가거나, 그 객체를 생성하는 데 
-비용이 많이 들거나, 어떤 방식으로든지 RealSubject에 대한 접근이 통제되어 있는 경우에 접근을 제어하는+비용이 많이 들거나, 어떤 방식으로든지 **%%RealSubject%%**에 대한 접근이 통제되어 있는 경우에 접근을 제어하는
 객체가 필요할 수 있습니다. 객체가 필요할 수 있습니다.
  
 지금까지 일반적인 프록시 패턴에 대해서 살펴봤습니다. 이제 프록시를 활용하는 다른 방법을 살펴보도록 하죠. 지금까지 일반적인 프록시 패턴에 대해서 살펴봤습니다. 이제 프록시를 활용하는 다른 방법을 살펴보도록 하죠.
 +
 +===== Virtual Proxy =====
 +방금 전에 프록시 패턴의 정의에 대해서 배웠습니다. 그리고 그 전에 살펴본 예제는 프록시 패턴 중이 하나인
 +원격 프록시(Remote Proxy)를 사용하는 예제였죠. 이제 가상 프록시(Virtual Proxy)라는 다른 형식의
 +프록시에 대해 살펴보겠습니다. 앞으로 계속해서 느낄 수 있겠지만, 프록시 패턴은 매우 다양한 형태로 쓰입니다.
 +하지만 어떤 형태로 사용하든 결국은 기본 프록시 디자인을 따르게 되죠. 어떻게 그렇게 다양한 형태로 활용될
 +수 있는 걸까요? 그 이유는 프록시 패턴은 여러 가지 다양한 상황에 적용될 수 있기 때문입니다.
 +
 +그럼 이제 가상 프록시의 예제를 살펴보도록 할까요?
 +
 +===== CD Cover Viewer =====
 +CD 커버를 보여주는 뷰어를 만들기로 했다고 가정해 봅시다. CD 타이틀 메뉴를 만든 다음 이미지를 아마존 닷 컴
 +같은 온라인 서비스로부터 가져오면 꽤 편리할 것입니다. 스윙을 사용한다면 아이콘을 만든 다음, 그 아이콘 객체
 +로 하여금 네트워크를 통해서 이미지를 불러오도록 할 수 있을 것입니다. 그런데, 이런 방법을 사용하면 네트워크의
 +상태와 인터넷 속도에 따라서 CD 커버 이미지를 가져오는데 약간 시간이 걸릴 수 있기 때문에, 이미지를 불러오는
 +동안 화면에 뭔가 다른 걸 보여주는 게 좋습니다. 그리고 이미지를 기다리는 동안 애플리케이션 전체가 작동을 멈추
 +는 것도 바람직하지 않죠.
 +
 +가상 프록시를 사용하면 이런 문제를 간단하게 해결할 수 있습니다. 가상 프록시가 아이콘 대신 백그라운드에서
 +이미지를 불러오는 작업을 처리하고, 이미지를 완전히 가져오기 전까지는 "Loading CD cover, please wait..."
 +같은 메세지를 보여주면 되니까요. 일단 이미지 로딩이 끝나고 나면 프록시에서는 아이콘 객체한테 모든 작업을
 +맡기면 됩니다.
 +
 +
 +===== Design of CD Cover viewer =====
 +CD 커버 뷰어 코드를 작성하기 전에 클래스 다이어그램을 살펴봅시다. 전에 만들었던 원격 프록시 클래스 다이어그램하고
 +똑같이 생겼지만, 여기에서는 프록시가 네트워크를 통해 연결되어 있는 다른 위치에 있는 객체를 대신하는 용도로 쓰인 것이 아니라
 +생성하는 데 많은 비용이 필요한 객체(아이콘용 데이터를 네트워크를 통해서 가져와야 하기 때문에 시간이 많이 걸릴 수
 +있죠)를 숨기기 위한 용도로 쓰입니다.
 +
 +{{:study:java:design_pattern:virtual_proxy.jpg|Virtual Proxy}}
 +
 +**%%ImageProxy%% 작동 방법**
 +
 +  - **%%ImageProxy%%에서는 우선 %%ImageIcon%%을 생성하고 네트워크 URL로부터 이미지를 불러옵니다.**
 +  - **이미지를 가져오는 동안에는 "Loading CD Cover, please wait..."라는 메세지를 화면에 표시합니다.**
 +  - **이미지 로딩이 끝나면 paintIcon(), getWidth(), getHeight()를 비롯한 모든 메소드 호출을 이미지 아이콘 객체한테 넘깁니다.**
 +  - **사용자가 새로운 이미지를 요청하면 프록시를 새로 만들고 위의 과정을 새로 진행합니다.**
 +
 +
 +
 +===== ImageProxy Class =====
 +<code java>
 +/**
 + * 네트워크를 통해서 이미지를 가져오는 동안 대신 실제객체를 대신하는 Proxy클래스입니다.<br/>
 + * imageIcon의 인스턴스가 만들어진 후에 화면을 표시하게 되면 paintIcon()메소드가 호출되면서 로딩중이라는
 + * 메시지가 아닌 실제 이미지가 화면에 표시됩니다.
 + 
 + * @author Administrator
 + *
 + */
 +public class ImageProxy implements Icon {
 + ImageIcon imageIcon;
 + URL imageURL;
 + Thread retrievalThread; //이미지를 가져오기위한 스레드, 사용자인터페이스가 죽지않도록 별도의 스레드를 생성.
 + boolean retrieving = false;
 +
 +
 + public ImageProxy(URL imageURL) {
 + super();
 + this.imageURL = imageURL;
 + }
 +
 + /* (non-Javadoc)
 + * @see javax.swing.Icon#getIconHeight()
 + */
 + public int getIconHeight() {
 + if (imageIcon != null) return imageIcon.getIconHeight();
 + else return 600;
 + }
 +
 + /* (non-Javadoc)
 + * @see javax.swing.Icon#getIconWidth()
 + */
 + public int getIconWidth() {
 + if (imageIcon != null) return imageIcon.getIconWidth();
 + else return 800;
 + }
 +
 + /* (non-Javadoc)
 + * @see javax.swing.Icon#paintIcon(java.awt.Component, java.awt.Graphics, int, int)
 + */
 + public void paintIcon(final Component c, Graphics g, int x, int y) {
 + if (imageIcon != null) {
 + //아이콘이 이미 준비되어 있으면 그 아이콘 객체의 메소드를 호출합니다.
 + imageIcon.paintIcon(c, g, x, y);
 + } else {
 + g.drawString("Loading CD cover, please wait...", x + 300, y + 190);
 + //이미지를 가져오고 있는 중이 아니면...
 + if (!retrieving) {
 + //이미지 로딩작업 시작.(repaint()메소드는 한 스레드에서만 호출하기 때문에, 스레드 안전성은 확보되었다고
 + //할 수 있습니다.
 + retrieving = true;
 +
 + //사용자 인터페이스가 죽지 않도록 별도의 스레드에서 이미지를 가져옵니다.
 + retrievalThread = new Thread(new Runnable(){
 + public void run(){
 + try {
 + //이 스레드 내에서 Icon객체의 인스턴스를 생성했습니다. 이미지가 완전히 로딩되어야 생성자에게 객체를 리턴합니다.
 + imageIcon = new ImageIcon(imageURL, "CD Cover");
 + //이미지가 확보되고 나면 repaint()메소드를 호출해서 화면을 갱신합니다.
 + c.repaint();
 + } catch (Exception e) {
 + e.printStackTrace();
 + }
 + }
 + });
 +
 + retrievalThread.start();
 + }
 + }
 +
 + }
 +
 +}
 +</code>
 +
 +
 +===== ImageComponent Class =====
 +<code java>
 +/**
 + * @author Administrator
 + *
 + */
 +public class ImageComponent extends JComponent {
 + private Icon icon;
 +
 + public ImageComponent(Icon icon) {
 + super();
 + this.icon = icon;
 + }
 +
 + public void setIcon(Icon icon) {
 + this.icon = icon;
 + }
 +
 + @Override
 + protected void paintComponent(Graphics g) {
 +  
 + super.paintComponent(g);
 + int w = icon.getIconWidth();
 + int h = icon.getIconHeight();
 + int x = (800 - w) / 2;
 + int y = (600 - h) / 2;
 + icon.paintIcon(this, g, x, y);
 + }
 +
 +
 +}
 +</code>
 +
 +
 +===== Test of CD Cover Viewer =====
 +드디어 새로 배운 가상 프록시를 테스트해 볼 때가 되었습니다. 윈도우를 만들고 프레임을 준비하고 메뉴를 설치하고
 +프록시를 생성해주는 %%ImageProxyTestDrive%%클래스를 미리 준비해 뒀습니다. 테스트용 클래스 코드는 다음과
 +같습니다.
 +
 +<code java>
 +public class ImageProxyTestDrive {
 + ImageComponent imageComponent;
 + JFrame frame = new JFrame("CD Cover View");
 + JMenuBar menuBar;
 + JMenu menu;
 + Hashtable cds = new Hashtable();
 + /**
 + * @param args
 + */
 + public static void main(String[] args) throws Exception{
 + ImageProxyTestDrive testDrive = new ImageProxyTestDrive();
 +
 + }
 +
 + public ImageProxyTestDrive() throws Exception{
 + cds.put("Ambient: Music for Airports", "http://images.amazon.com/images/P/B000003S2K.01.LZZZZZZZ.jpg");
 + cds.put("Buddha Bar", "http://images.amazon.com/images/P/B00009XBYK.01.LZZZZZZZ.jpg");
 + cds.put("Ima", "http://images.amazon.com/images/P/B000005IRM.01.LZZZZZZZ.jpg");
 + cds.put("Karma", "http://images.amazon.com/images/P/B000005DCB.01.LZZZZZZZ.jpg");
 + cds.put("MCMXC A.D.", "http://images.amazon.com/images/P/B000002URV.01.LZZZZZZZ.jpg");
 + cds.put("Northern Exposure", "http://images.amazon.com/images/P/B000003SEN.01.LZZZZZZZ.jpg");
 + cds.put("Selected Ambient Works, Vol. 2", "http://images.amazon.com/images/P/B000002MNZ.01.LZZZZZZZ.jpg");
 + cds.put("oliver", "http://www.cs.yale.edu/homes/freeman-elisabeth/2004/9/Oliver_sm.jpg");
 +
 + URL initialURL = new URL((String)cds.get("Selected Ambient Works, Vol. 2"));
 + menuBar = new JMenuBar();
 + menu = new JMenu("Favorite CDs");
 + menuBar.add(menu);
 + frame.setJMenuBar(menuBar);
 +
 + for (Enumeration e = cds.keys(); e.hasMoreElements();) {
 + String name = (String)e.nextElement();
 + JMenuItem menuItem = new JMenuItem(name);
 + menu.add(menuItem);
 + menuItem.addActionListener(new ActionListener(){
 + public void actionPerformed(ActionEvent event){
 + imageComponent.setIcon(new ImageProxy(getCDUrl(event.getActionCommand())));
 + frame.repaint();
 + }
 + });
 +
 + }
 +
 + //프레임 및 메뉴 설정
 + Icon icon = new ImageProxy(initialURL);
 + imageComponent = new ImageComponent(icon);
 + frame.getContentPane().add(imageComponent);
 + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 + frame.setSize(800, 600);
 + frame.setVisible(true);
 + }
 +
 + URL getCDUrl(String name){
 + try {
 + return new URL((String)cds.get(name));
 + } catch (MalformedURLException e) {
 + e.printStackTrace();
 + return null;
 + }
 + }
 +}
 +</code>
 +
 +**테스트 해 볼 것...**
 +  - **메뉴를 이용하여 다른 CD 커버를 불러옵니다. 이미지 로딩이 완료될 때까지 프록시에서 로딩중이라는 메세지를 보여주는 것을 확인해 봐야 되겠죠?**
 +  - **로딩중이라는 메시지가 화면에 표시된 상태에서 윈도우 크기를 조절해 봅시다. 프록시에서 이미지를 로딩하고 있을 때도 스윙 윈도우가 멈추거나 하진 않는지 확인해 봅시다.**
 +  - **%%ImageProxyTestDrive%%에 여러분이 가지고 있는 CD를 추가해 봅시다.**
 +다음은 로딩중일 때의 화면입니다.
 +
 +{{:study:java:design_pattern:loading.jpg|under loding}}
 +
 +로딩이 완료되면 이런 윈도우가 만들어집니다.
 +
 +{{:study:java:design_pattern:oliver.jpg|oliver}}
 +
 +===== reference =====
 +  *[[http://www.syboos.jp/sysdesign/doc/20080624135350826.html?page=1|an example of Protection Proxy pattern
 +]]
 +
 +
 +
  
  

QR Code
QR Code study:java:design_pattern:proxy (generated for current page)