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#]
// 총정리 - 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(의존관계 역전 원칙) : 구체 클래스에 의존하는 것이 아니라
// 추상 클래스나 인터페이스에 의존해야 한다.