00200 20151218 자바 GoF 디자인패턴 수업 10일차 - AngryQA/blog GitHub Wiki

자바 GoF 디자인패턴 수업 10일차

AngryQA | 2015-12-18 금요일 오전 9:44 | IT/개발전반 | 원본

1. 해쉬코드에 대해

[#M_더보기|접기|

import java.util.HashMap; import java.util.Map; import java.util.Objects;

// 1. hashcode 값은 key를 계산하기 위한 용도. // 2. 같은 해시 값 안에서는 equals를 통해 해당 객체를 // 찾아낸다. // (equals를 정의하지 않으면, 모든 객체는 자기 자신하고만 // 동일하다) // 3. hashCode 는 탐색의 성능을 보장하기 위해 제공되어야 한다. // 4. eqauls 는 동등성을 제공하기 위해 만들어야 한다.

public class Example1 { public static void main(String[] args) { Point p1 = new Point(10, 20); Point p3 = new Point(10, 20); Point p2 = new Point(30, 40);

 System.out.println(p1);
 System.out.println(p2);

 Map map = new HashMap();
 map.put(p1, "Hello");
 // map.put(p2, "World");

 System.out.println(map.get(p3));
 // System.out.println(map.get(p2));

}

}

class Point { private int x; private int y;

@Override public int hashCode() { return 0; }

@Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (!(o instanceof Point)) return false; Point p = (Point)o; return Objects.equals(x, p.x) && Objects.equals(y, p.y); }

public Point(int x, int y) { this.x = x; this.y = y; } 

}

_M#]

2. Flyweight Pattern (경량패턴)

: 속성과 동일한 객체가 다수 생성된다면 하나의 객체를 공유해서 사용하자

[#M_대상소스|접기|

// Flyweight Pattern // : 속성과 동일한 객체가 다수 생성된다면 // 하나의 객체를 공유해서 사용하자. public class Example2 { public static void main(String[] args) { Image image1 = new Image("http://www.a.com/a.png"); image1.draw();

 Image image2 = new Image("http://www.a.com/a.png");
 image2.draw();

} }

class Image { private String url; public Image(String url) { this.url = url;

 System.out.println("Loading Image from  "  + url);
 try {
   Thread.sleep(3000);
 } catch (InterruptedException e) {
   e.printStackTrace();
 }

}

public void draw() { System.out.println("Draw Image"); } 

}

_M#]

방법 1 팩토리를 통한 경량패턴 규현 

[#M_더보기|접기|

import java.util.HashMap; import java.util.Map;

// 방법 1. 팩토리를 통한 경량 패턴 구현. interface IImage { void draw(); }

class ImageFactory { private static final ImageFactory INSTANCE = new ImageFactory();

public static ImageFactory getInstance() { return INSTANCE; }

private Map imageMap = new HashMap();

public IImage createImage(String url) { if (!imageMap.containsKey(url)) imageMap.put(url, new Image(url));

 return imageMap.get(url);

}

private static class Image implements IImage { private String url;

 public Image(String url) {
   this.url = url;

   System.out.println("Loading Image from  "  + url);
   try {
     Thread.sleep(3000);
   } catch (InterruptedException e) {
     e.printStackTrace();
   }
 }

 public void draw() {
   System.out.println("Draw Image");
 }

} }

public class Example4 { public static void main(String[] args) { ImageFactory factory = ImageFactory.getInstance(); IImage image1 = factory.createImage("http://www.a.com/a.png"); IImage image2 = factory.createImage("http://www.a.com/a.png");

 // Image image = new Image("...");

 image1.draw();
 image2.draw();

} }

_M#]

방법2 정적 팩토리 메소드

[#M_더보기|접기|

import java.util.HashMap; import java.util.Map;

public class Example5 { public static void main(String[] args) { Image image1 = Image.imageWithURL("http://www.a.com/a.png"); Image image2 = Image.imageWithURL("http://www.a.com/a.png");

 image1.draw();
 image2.draw();

} }

// 방법 2. 정적 팩토리 메소드를 이용한 경량 패턴 // Wrapper Class : Integer, Long, Boolean ... // values.add(10); -> values.add(Integer.valueOf(10))

// Flyweight 패턴에서 주의할 점 // -> Immutable Object로 제공되어야 한다.

// Function -> Pure Function // f(x1, x2) => y // : 수학적 함수의 형태를 프로그래밍적으로 구현하는 것

class Image { private String url; private Image(String url) { this.url = url;

 System.out.println("Loading Image from  "  + url);
 try {
   Thread.sleep(3000);
 } catch (InterruptedException e) {
   e.printStackTrace();
 }

}

private static Map imageMap = new HashMap(); public static Image imageWithURL(String url) { if (!imageMap.containsKey(url)) imageMap.put(url, new Image(url)); return imageMap.get(url); }

public void draw() { System.out.println("Draw Image"); Integer } 

}

_M#]

방법 3 자바 8에서 인터페이스로 구현

[#M_더보기|접기|

import java.util.HashMap;

import java.util.Map;

// Java 8 - 인터페이스를 이용한 경량 패턴.

public class Example6 { public static void main(String[] args) { Image image1 = Image.imageWithURL("http://www.a.com/a.png"); Image image2 = Image.imageWithURL("http://www.a.com/a.png");

 image1.draw();
 image2.draw();

} }

interface Image { void draw();

Map imageMap = new HashMap();

static Image imageWithURL(String url) { if (!imageMap.containsKey(url)) imageMap.put(url, new DefaultImage(url)); return imageMap.get(url); }

class DefaultImage implements Image { private String url;

 DefaultImage(String url) {
   this.url = url;

   System.out.println("Loading Image from  "  + url);
   try {
     Thread.sleep(3000);
   } catch (InterruptedException e) {
     e.printStackTrace();
   }
 }

 @Override
 public void draw() {
   System.out.println("Draw Image");
 }

} }

_M#]

3. 

버추얼 프락시

대리자 객체

프로그램의 시작을 개선

Proxy Patton (대리자 패턴)

처리 과장이 복잡하거나 리소스 많이 차지 하는 객체가 있을때, 대리자를 두어 대리자가 간단한 일 처리

실제 해당해는 객체가 필요할때 생성...

[#M_더보기|접기|

import java.util.ArrayList; import java.util.List;

// Virtual Proxy

// 1. 이미지를 사용하는 방법은 인터페이스로 약속되어야 한다. interface Image { void draw();

// 2. 이미지 객체를 생성하는 방법이 제공되어야 한다. static Image imageWithURL(String url) { // return new RealImage(url); return new ProxyImage(url); } }

// 3. 객체의 생성 비용이 크다면, 가짜 대리자 객체를 대신 사용하고 // 진짜로 필요한 시점에 이용할 수 있도록 하자. class ProxyImage implements Image { private String url; private RealImage image;

public ProxyImage(String url) { this.url = url; }

@Override public void draw() { if (image == null) { System.out.println("Loading Image..."); image = new RealImage(url); }

 image.draw();

} }

public class Example8 { public static void main(String[] args) { Dialog dialog = new Dialog(); dialog.show(); } }

class Dialog { private List imageList = new ArrayList();

public Dialog() { imageList.add(Image.imageWithURL("http://www.a.com/a.png")); imageList.add(Image.imageWithURL("http://www.a.com/b.png")); imageList.add(Image.imageWithURL("http://www.a.com/c.png")); }

public void show() { System.out.println("Dialog show"); imageList.get(0).draw(); } }

class RealImage implements Image { private String url;

public RealImage(String url) { this.url = url;

 loadImage();

}

private void loadImage() { System.out.println("Loading RealImage from " + url); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } }

public void draw() { System.out.println("Draw image " + url); } 

}

_M#]

프록시 테스트 소스

[#M_적용전|접기|

import javax.swing.*;

import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map;

class ImageComponent extends JComponent { private Icon icon;

public ImageComponent(Icon icon) { this.icon = icon; }

public void setIcon(Icon icon) { this.icon = icon; }

public void paintComponent(Graphics g) { super.paintComponent(g);

 int w = icon.getIconWidth();
 int h = icon.getIconHeight();
 int x = (800 - w) / 2;
 int y = (800 - h) / 2;
 icon.paintIcon(this, g, x, y);

}

}

class CoverViewer { private JFrame frame = new JFrame("CD Cover Viewer"); private JMenuBar menuBar; private JMenu menu; private Map cds = new HashMap();

private ImageComponent imageComponent;

public CoverViewer() throws Exception { cds.put("Cover1", "http://cdn.shopify.com/s/files/1/0211/4926/files/P-Beatles2__ZOOM.jpg"); cds.put("Cover2", "http://cdn.shopify.com/s/files/1/0211/4926/files/P-Beatles2__ZOOM.jpg"); cds.put("Cover3", "http://cdn.shopify.com/s/files/1/0211/4926/files/P-Beatles2__ZOOM.jpg");

 URL initialUrl = new URL(cds.get("Cover1"));

 menuBar = new JMenuBar();
 menu = new JMenu("Favorite CDs");
 menuBar.add(menu);
 frame.setJMenuBar(menuBar);

 for (String name : cds.keySet()) {
   JMenuItem menuItem = new JMenuItem(name);
   menu.add(menuItem);

   menuItem.addActionListener(new ActionListener() {
     @Override
     public void actionPerformed(ActionEvent e) {
       imageComponent.setIcon(new ImageIcon(getCDUrl(e
           .getActionCommand())));
       frame.repaint();
     }

   });
 }

 Icon icon = new ImageIcon(initialUrl);
 imageComponent = new ImageComponent(icon);
 frame.getContentPane().add(imageComponent);
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 frame.setSize(800, 800);
 frame.setVisible(true);

}

private URL getCDUrl(String name) { try { return new URL(cds.get(name)); } catch (MalformedURLException e) { e.printStackTrace(); return null; } }

}

public class Example9 { public static void main(String[] args) throws Exception { CoverViewer coverViewer = new CoverViewer(); } }

_M#][#M_적용후|접기|

import javax.swing.; import java.awt.; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map;

// Proxy Pattern(대리자 패턴) // : 처리 과정이 복잡하거나, 시스템의 리소스를 많이 필요로 하거나 // 하는 객체가 있을 때, 대리자를 두어 간단한 일은 대리자가 처리하고 // 실제 해당하는 객체가 필요할 때 생성하여 처리.

// Proxy Pattern 종류 // 1) Remote Proxy : 원격 객체에 대한 로컬의 대리자 // - RMI(Remote Method Invoke) // - RPC(Remote 프로시저 Call) // 2) Virtual Proxy : 많은 비용을 요구하는 객체를 생성하는 경우 // 프로그램의 로딩 속도가 느려지므로, // 대리자를 두어 진짜 필요할 때 생성하는 기법. // 3) Protection Proxy : 보호가 요구되는 객체에 접근을 통제하는 대리자 // Collection.undifiedColleciton // Collection.synchronizedCollection

// http://d.pr/n/1aLfG class ImageComponent extends JComponent { private Icon icon;

public ImageComponent(Icon icon) { this.icon = icon; }

public void setIcon(Icon icon) { this.icon = icon; }

public void paintComponent(Graphics g) { super.paintComponent(g);

 int w = icon.getIconWidth();
 int h = icon.getIconHeight();
 int x = (800 - w) / 2;
 int y = (800 - h) / 2;
 icon.paintIcon(this, g, x, y);

} }

// http://d.pr/n/UW8V class ImageProxy implements Icon { private URL url; private ImageIcon icon;

public ImageProxy(URL url) { this.url = url; }

@Override public void paintIcon(Component c, Graphics g, int x, int y) { if (icon != null) icon.paintIcon(c, g, x, y); else { g.drawString("Loading CD Cover, wait...", x + 300, y + 300);

   Thread loadingThread = new Thread(new Runnable() {
     @Override
     public void run() {
       icon = new ImageIcon(url);
       c.repaint();
     }
   });
   loadingThread.start();
 }

}

@Override public int getIconWidth() { if (icon != null) return icon.getIconWidth(); return 800; }

@Override public int getIconHeight() { if (icon != null) return icon.getIconHeight(); return 800; } }

class CoverViewer { private JFrame frame = new JFrame("CD Cover Viewer"); private JMenuBar menuBar; private JMenu menu; private Map cds = new HashMap();

private ImageComponent imageComponent;

public CoverViewer() throws Exception { cds.put("Cover1", "http://cdn.shopify.com/s/files/1/0211/4926/files/P-Beatles2__ZOOM.jpg"); cds.put("Cover2", "http://cdn.shopify.com/s/files/1/0211/4926/files/P-Beatles2__ZOOM.jpg"); cds.put("Cover3", "http://cdn.shopify.com/s/files/1/0211/4926/files/P-Beatles2__ZOOM.jpg");

 URL initialUrl = new URL(cds.get("Cover1"));

 menuBar = new JMenuBar();
 menu = new JMenu("Favorite CDs");
 menuBar.add(menu);
 frame.setJMenuBar(menuBar);

 for (String name : cds.keySet()) {
   JMenuItem menuItem = new JMenuItem(name);
   menu.add(menuItem);

   menuItem.addActionListener(new ActionListener() {
     @Override
     public void actionPerformed(ActionEvent e) {
       imageComponent.setIcon(new ImageIcon(getCDUrl(e
           .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, 800);
 frame.setVisible(true);

}

private URL getCDUrl(String name) { try { return new URL(cds.get(name)); } catch (MalformedURLException e) { e.printStackTrace(); return null; } }

}

public class Example9 { public static void main(String[] args) throws Exception { CoverViewer coverViewer = new CoverViewer(); } }

_M#]

20151218.zip


// 총정리 - GoF 디자인 패턴 22가지 // 생성 5가지 // - Singleton : 오직 하나의 객체를 생성, 어디서든 동일한 방법으로 접근 // - Factory Method : 객체 생성에 관련된 가변성을 메소드로 분리 // - Absract Factory : 공장도 인터페이스 기반으로 // - Prototype : 견본에 의한 생성 // - Builder : 동일한 구축 공정, 다른 표현 객체 생성

// 구조 7가지 // - Composite : 재귀적 합성을 통한 복합 객체 구성 // - Decorator : 재귀적 합성을 통한 동적인 기능의 추가 // - Adpater : 인터페이스의 변경 // - Bridge : 구현과 추상을 분리 // - Proxy : 기존 요소를 대신하는 클래스 // - Facade : 하위 시스템의 복잡함을 단순화 시키는 상위 클래스 제공 // - Flyweight : 속성이 동일한 객체는 공유

// 행위 10가지 // - Template Method : 변하는 정책을 메소드로 분리 // - State : 상태에 따른 동작을 인터페이스 기반 클래스로 분리 // - Strategy : 정책을 인터페이스 기반 클래스로 분리 // - Iterator : 복합 객체의 내부 구조에 상관없이 요소를 열거 // - Visitor : 복합 객체의 내부 구조에 상관없이 요소에 연산 // - Observer : 발생한 이벤트를 등록된 객체에게 전파 // - Chain of Responsibility : 발생한 이벤트가 처리되지 않으면 // 다음 객체에게 전달 // - Memento : 객체의 상태 저장/복원을 제공하는 방법 // - Command : 명령을 캡슐화, undo, redo, macro... // - Mediator : 객체 간의 복잡한 관계를 캡슐화

// 그 외 // - Static Factory Method // - Singleton - Enum, IODH // - Reflection // - Java 8 : interface, Stream API, Lambda // - Thread : Concurrent Package // - NIO(1.4), NIO2(1.7) // - Strong, Weak, Soft Reference // - Immutable Object // - Object(clone, hashCode, equals, finalize)

// 객체지향 5대 원칙(SOLID) // - SRP(단일 책임 원칙) : 모듈은 단 하나의 책임을 가져야 한다. // - OCP(개방 폐쇄 원칙) : 모듈은 수정에는 닫혀 있고, 확장에는 열려 있어야 한다. // - LSP(리스코프 대체 원칙) : 자식의 공통된 속성은 부모로부터 와야 한다. // - ISP(인터페이스 분리 원칙) : 범용 인터페이스보다 세분화된 인터페이스가 낫다. // - DIP(의존관계 역전 원칙) : 구체 클래스에 의존하는 것이 아니라 

// 추상 클래스나 인터페이스에 의존해야 한다.

source.zip

Attachments(2)