'Pattern'에 해당되는 글 16건

  1. 2008.04.21 facade pattern by 파이팅야 3
  2. 2008.04.18 adapter pattern by 파이팅야 2
  3. 2008.04.17 prototype pattern by 파이팅야 2
  4. 2008.04.17 bridge pattern by 파이팅야 1
  5. 2008.04.15 composite pattern by 파이팅야 3
  6. 2008.04.11 abstract factory pattern by 파이팅야 2

facade pattern

Pattern 2008. 4. 21. 11:02
1. 개요

Facade 패턴은 복잡한 서브 시스템에 통일된 인터페이스를 제공함으로써 복잡한 API를 단순화 시켜준다. 시스템을 서브 시스템 단위로 나누어 구성하는 것은 시스템의 복잡도를 낮춰주지만, 동시에 서브 시스템 사이에서의 통신 부하와 결합도가 증가하게 된다. 이러한 서브 시스템 사이의 의존도를 낮추고, 서브 시스템의 사용자 입장에서 사용하기 편리한 인터페이스를 제공하고자 하는 것이 facade 객체이다.

사용자 삽입 이미지

실생활에서의 고객 서비스 센터와 유사하다. 가령, 어떤 상품을 구매하는 과정에서 문제가 생겼다고 가정할 때, 고객이 문제의 성격에 따라 해당 부서에 직접 연락하는 것이 아니라 고객 서비스 센터를 통하는 것은 Facade 패턴에 대한 좋은 유추 사례가 될 수 있다.

2. 적용 영역

■ 복잡한 서브 시스템에 대해 간단한 인터페이스를 제공하기를 원하는 경우
■ 클라이언트와 인터페이스의 구현 클래스 사이에 의존도가 높은 경우
■ 서브 시스템을 레이어(layer)로 구분하고자 하는 경우


3.
참가자들(participants)
  The classes and/or objects participating in this pattern are:

  • Facade   (MortgageApplication)
    • knows which subsystem classes are responsible for a request.
    • delegates client requests to appropriate subsystem objects.
  • Subsystem classes   (Bank, Credit, Loan)
    • implement subsystem functionality.
    • handle work assigned by the Facade object.
    • have no knowledge of the facade and keep no reference to it.

5. 적용 결과
서브 시스템의 컴포넌트로부터 클라이언트를 격리하여, 클라이언트가 쉽게 서브 시스템을 이용할 수 있다.
서브 시스템과 클라이언트 사이의 의존성을 낮춘다.
■ Facade
패턴을 사용한다고 해도, 필요한 경우 서브 시스템의 클래스에 직접 접근할 수도 있다. , 일반화 정도(generality)와 개발의 편의성 사이에서의 적당한 합의점을 찾아야 한다.

6. 예제

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

 

class FacadeTest extends JFrame
{

 private JFrame frame;
 private JPanel panel;
 private JTextArea MainWindow;
 private JScrollPane sp1;
 private JTextField ChatWindow;
 private JButton SendButton;
 private JTextArea UserWindow;
 private JScrollPane sp2;


 public FacadeTest()

 {
 }

 

 public void createUI()
 {

  setTitle("Facade Test");
  setBounds(0, 0, 467, 260);
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


  panel = new JPanel();
  panel.setLayout(null);
  add(panel, BorderLayout.CENTER);
 
  MainWindow = new JTextArea();
  sp1 = new JScrollPane(MainWindow);
  MainWindow.setLineWrap(true);
  MainWindow.setEditable(false);
  sp1.setBounds(5, 5, 300, 198);
  panel.add(sp1);

 

  ChatWindow = new JTextField();
  ChatWindow.setBounds(5, 205, 230, 25);
  panel.add(ChatWindow);

 

  SendButton = new JButton("Send");
  SendButton.setBounds(238, 206, 64, 23);

  panel.add(SendButton);

 

  UserWindow = new JTextArea();
  sp2 = new JScrollPane(UserWindow);
  UserWindow.setEditable(false);
  sp2.setBounds(310, 5, 145, 225);
  panel.add(sp2);

 

  setResizable(false);
  show();

 }

 

 public static void main(String[] args)
 {

FacadeTest facade = new FacadeTest();
facade.createUI();

 }

}

7. 참고

  http://en.wikipedia.org/wiki/Facade_pattern


Posted by 파이팅야
,

adapter pattern

Pattern 2008. 4. 18. 13:15

Adapter Pattern은 특정 클래스의 인터페이스를 클라이언트가 기대하는 다른 인터페이스로 전환시킨다.

인터페이스가 호환되지 않아 상호작용할 수 없는 경우에, Adapter를 이용하여 클래스 사이의 인터페이스의 호환성을 보장 가능함.

 (Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.)

- 새로운 인터페이스로 클래스를 감싸게 되기 때문에 Wrapper 패턴이라고도 함.

- Bridge 패턴은 Object Adapter와 유사한 구조를 갖고 있지만, 서로 의도가 다르다. Adapter는 존재하고 있는 객체에 대한 인터페이스를 바꾸기 위한 의도를 갖지만, Bridge는 인터페이스를 해당 구현체(implementation)분리하기 위한 의도를 띈다

- 아래와 같이 적용하는 패턴의 방법은 2가지가 있다.

1) Class Adapter pattern 

다중상속으로 구현하는 방법. Java에서는 다중상속 안됨. C++에서 사용하면 됨

사용자 삽입 이미지

2) Object Adapter pattern 

Object를 이용해서 구현하는 방법.

(예로 Adapter의 생성자에서 adaptee를 생성해서 Operation1()에서 adaptee.Operation2()를 호출함)

 

사용자 삽입 이미지

ㅇ. 구현 예


ㅇ. 소스

public abstract class Unit {
abstract void move();
abstract void attack();
}
public class Marine extends Unit {
void attack() {
System.out.println("탕탕탕(마린 공격)");
}
void move() {
System.out.println("튀튀 ~~~ (마린 이동)");
}
}
public class Hydralisk extends Unit {
void attack() {
System.out.println("툇!툇!(히드라 침뱉는 소리)");
}
void move() {
System.out.println("엉금 엉금 (히드라 이동)");
}
}
public class Ghost extends Unit {
public Ninja ninja = null;
public Ghost() {
this.ninja = new Ninja();
}
void attack() {
this.ninja.cut();
}
void move() {
this.ninja.walk();
}
}
public class Battlecruiser extends Unit {
public Airwolf airwolf = null;
public Battlecruiser() {
this.airwolf = new Airwolf();
}
void attack() {
this.airwolf.shoot();
}
void move() {
this.airwolf.fly();
}
}
public class Ninja {
public void walk() {
System.out.println("걷기");
}
public void cut() {
System.out.println("자르기");
}
}
public class Airwolf {
public void fly() {
System.out.println("날기");
}
public void shoot() {
System.out.println("총쏘기");
}
}
public class Client {
public static void main(String[] args) {
System.out.println("-- Ghost --");
Unit ghost = new Ghost();
ghost.move();
ghost.attack();
System.out.println("-- Battlecruiser --");
Unit battlecruiser = new Battlecruiser();
battlecruiser.move();
battlecruiser.attack();
}
}

-- Ghost --
걷기
자르기
-- Battlecruiser --
날기
총쏘기

ㅇ. 참고

- wikipedia : 

http://en.wikipedia.org/wiki/Adapter_pattern

- 위키피디아 : 

http://ko.wikipedia.org/wiki/%EC%96%B4%EB%8C%91%ED%84%B0_%ED%8C%A8%ED%84%B4

Posted by 파이팅야
,

prototype pattern

Pattern 2008. 4. 17. 18:00

Prototype Pattern은 클래스로부터 인스턴스를 생성하는 것이 아니라, 인스턴스로부터 인스턴스를 생성하게 된다

(Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype)

- ConcretePrototype 클래스에서 복사본을 생성할 때 단순 복사본(Shallow Copy)을 생성한다는 것을 알 수 있다. 닷넷에서는 단순 복사본을 생성하는 메서드 MemberwiseClone()이 제공된다. Java Clone()이 제공된다.

- 단순 복사본(Shallow Copy)은 원본의 참조를 유지하지만 전체 복사본(Deep Copy)은 원본의 참조를 유지하지 않고 참조되는 객체의 새로운 복사본을 참조한다.

객체 X가 객체 A, B를 참조하고, 객체 A는 객체 M을 참조한다고 할 때 X에 대한 단순 복사본 Y는 객체 A B를 참조한다.Deep Copy new()해서 생성된 것이라 생각하면 쉬울 것 같다.
- 활용성 ==> 인스턴스화할 클래스를 런타임에 지정할 때, 클래스의 인스턴스들이 서로 다른 상태 조합 중에 어느 하나일 때
- 관련 패턴 ==> 추상 팩토리 패턴과는 어떤 면에서 경쟁적인 관계이다. 하지만 함께 사용될 수도 있다. 추상 팩토리 패턴은 원형 집합을 저장하다가 필요할 때 복제하여 제품 객체를 반환하도록 사용할 수도 있다. 복합체 패턴과 장식자 패턴을 많이 사용해야 하는 설계에서 원형 패턴을 사용해서 재미를 볼수도 있다.

사용자 삽입 이미지

public abstract class AColorBase implements Cloneable {

       public abstract AColorBase createClone();

--------------------------------------------------------------

public class Color extends AColorBase {

       private int red;

       private int green;

       private int blue;

 

       public Color(int red, int green, int blue) {

             this.red     = red;

             this.green   = green;

             this.blue    = blue;

       }

       public AColorBase createClone() {

             AColorBase aColorBase = null;

             try {

                    aColorBase =(AColorBase)this.clone();

             } catch (CloneNotSupportedException e) {

                    e.printStackTrace();

             }

             return aColorBase;

       }

       public String toString() {

             return String.format("red[%d], green[%d], blue[%d]", this.red, this.green, this.blue);

       }

       Getter/ Setter …

--------------------------------------------------------------

public class ColorManager {

       private Hashtable<String, AColorBase> colorTable;

       public ColorManager() {

             colorTable = new Hashtable<String, AColorBase>();

       }

       public AColorBase register(String colorName, AColorBase colorBase) {

             return colorTable.put(colorName, colorBase);

       }

       public AColorBase create(String colorName) {

             return colorTable.get(colorName).createClone();

       }

--------------------------------------------------------------

public class Client {

  public static void main(String[] args) {

        // 인스턴스 만들기

        Color green = new Color(0, 200, 0);

        ColorManager colorManager = new ColorManager();

        colorManager.register("red", new Color(200, 0, 0));

        colorManager.register("green", green);

        colorManager.register("blue", new Color(0, 0, 200));

 

        // 외부:인스턴스 만들기, 내부:인스턴스 복사

        // 복사(clone)되기 때문에 생성의 부하가 적음

        AColorBase newColor = colorManager.create("red");

        System.out.println(newColor);

 

        newColor = colorManager.create("green");

        System.out.println(newColor);

--------------------------------------------------------------
red[200], green[0], blue[0]

red[0], green[200], blue[0]


  • 구현 관련
    • 위의 구현형태는 하나의 클래스로부터 상태값이 다른 여러 객체를 생성하고, 생성된 객체들을 복사해서 사용하는 형태이다. 이와 다르게 AColorBase와 같은 Prototype 클래스을 구현하는 여러개의 클래스들의 객체를 각각 생성하고 생성된 객체들을 복사해서 사용해도 된다. 상황에 따라서 적절히 선택해서 구현하면 된다.
    • ColorManager와 같은 Prototype Manager 객체는 register(생성), unRegister(제거), check(확인)와 같은 메소드들을 일반적으로 제공한다.
    • 그림판의 왼쪽에 있는 palette가 ColorManager와 비슷한 형태이고, palette에서 선택한 도형을 그림판에서 생성할때 마다 clone 되어 생성되는 형태이다. 사용자에 의해 실시간으로 도형을 생성하기 위해서는 palette와 같은 형태의 class가 있어야 한다. 예를 들면 사용자에 의해 선택된 2가지의 도형을 합친 새로운 도형을 만들고자 하면 palette에 두가지 도형에 대해 composite pattern을 사용해서 등록하고 사용하면 된다.
    • 참고

Posted by 파이팅야
,

bridge pattern

Pattern 2008. 4. 17. 11:02


  • 개요
    • 추상화 부분과 구현 부분을 분리시켜 서로 독립적으로 확장 가능하게 한다. (Decouple an abstraction from its implementation so that the two can vary independently)
    • 아래의 Class Digram에서 추상화 부분은 AProgram, Program 부분이고 구현 부분은 Aalgorithm, Algorithm1, Algorithm2 부분이다. Client는 추상화 부분만 알게되고 실제적으로 내부구현 부분이 있는 구현 부분에 대해서는 모르게 된다. 따라서 구현 부분이 바뀌어도 Client에 제공되는 추상화 interface 부분은 변경이 없다.
    • ProgramA와 ProgramB가 Algorithm1이나 Algorithm2에 따라서 다르게 동작하는 경우(리모콘이 있는데 여러 TV제품사 별로 채널변경하는 기능이 다른 경우, SearchEngine이 있는데 OS별로 Search방법이 다른 경우)에 client에게 interface를 담당하는 Program부분과 실제로 처리하는 로직 및 비즈니스를 구현하는 Algorithm를 서로 분리해서 독립적으로 확장 가능하게 한다. 만약 이런 구조가 아니면 AProgram을 구현하는 Algorithm1ProgramA, Algorithm2ProgramB와 같이 구현되는 형태가 되므로 class들이 많이 증가하게 되므로 추가 및 수정에 용이하지 않다.
  • 문제 예

  • 소스
public abstract class Aalgorithm {
abstract int calculate(int num);
}
public class Algorithm1 extends Aalgorithm {
int calculate(int num) {
return (num + 2) * 10;
}
}
public class Algorithm2 extends Aalgorithm {
int calculate(int num) {
return (num - 1) + 200 * 123;
}
}
public abstract class AProgram {
int num = 0;
Aalgorithm algorithm = null;
public AProgram(int num, Aalgorithm algorithm) {
this.num = num;
this.algorithm = algorithm;
}
public abstract int cal();
}
public class Program extends AProgram {
public Program(int num, Aalgorithm algorithm) {
super(num, algorithm);
}
public int cal() {
return this.algorithm.calculate(this.num);
}
}
public class Client {
public static void main(String[] args) {
AProgram prog1 = new Program(2, new Algorithm1());
AProgram prog2 = new Program(5, new Algorithm2());

int result1 = prog1.cal();
int result2 = prog2.cal();
System.out.println("result1[" + result1 + "]");
System.out.println("result2[" + result2 + "]");
}
}
-------------------------
result1[40]
result2[24604]

  • 구현 관련
    • Program 부분을 Template Class 형태로 변경하면 Client에서 다음과 같이 사용할 수도 있다. (아래의 '위키피디아' 링크의 내용 중 '이름을 사용한 c#'부분의 내용 참고)
      • AProgram prog1 = new Program<Algorithm1>(2);
      • AProgram prog2 = new Program<Algorithm2>(2);
    •  AProgram에서 다음과 같이 수정하게 되고 Program에서는 algorithm의 값을 바로 사용하는 형태가 되면, 추후 algorithm이 추가될때 마다 소스를 수정해 줘야 하는 단점이 있다. 차라리 Abstract Factory나 Factory Method를 사용해도 될것 같다.
      • 변경 전  : Aalgorithm algorithm = null;
      • 변경 후 : 
        • #ifdef _ALG1
          • Aalgorithm algorithm = new Algorithm1();
        • #else
          • Aalgorithm algorithm = new Algorithm2();
        • #end if
    • Progam에서 num값이 10 이상이면 algorithm1이 실행되고, 10미만이면 algorithm2가 실행되게 사용할 수 있다.
  • 차이점
    • Adapter Pattern 은 이미 존재하는 객체를 이용해서 다른 객체의 인터페이스를 만들어 주기 위한 목적으로 쓰이나, Bridge패턴은 추상화 부분과 구현 부분을 분리해서 독립적으로 확장하고자 하기 위한것이다. 즉 Bridge Pattern은 분리를 할려고 하고 Adapter는 재활용 할려고 한다.

  • 참고


Posted by 파이팅야
,

composite pattern

Pattern 2008. 4. 15. 21:02

Composite 패턴은 부분에서 전체에 이르는 계층 구조를 구축하거나 Tree형 자료 명세 내역을 생성하기 위해 사용될 수 있다. 

예를 들어 폴더와 파일을 합해서 [폴더 엔트리]로 취급하듯이 그릇과 내용물을 같은 종류로 취급하는 경우다. 이와 같이 특정 [객체들](파일)[그것들을 포함하는 객체들](폴더)을 동일하게 다룰 수 있게 해주는 패턴 Composite 패턴이라고 한다.

 

 File는 아무것도 포함할 수 없고 포함되는 역할을 하며, Folder는 File이나, 다른 Folder를 포함 할 수 있다. File의 operation()과 Folder의 operation()은 각각 다르게 동작한다.
(만약 HTML Parser를 구현한다면 Folder=Element, File=Attribute가 될 것이다.)
사용예) HTML DOM, XML

사용자 삽입 이미지


 

public abstract class AComponent {

             private String name;

             public String getName() {…}

             public void setName(String name) {…}

 

             protected abstract void operation(int depth);

             protected abstract void add(AComponent aComponent);

             protected abstract void remove(AComponent aComponent);

---------------------------------------------------------------------------

public class File extends AComponent {

             public File(String name) {

                           super.setName(name);

             }

             protected void operation(int depth) {

                           for (int i = 0; i < depth; i++)

                                        System.out.print("-");

                           System.out.println(" " + super.getName());

             }

             protected void add(AComponent component) {}

             protected void remove(AComponent component) {}
---------------------------------------------------------------------------

public class Folder extends AComponent {

             private List<AComponent> componentList = null;

             public Folder(String name) {

                           super.setName(name);

                           componentList = new ArrayList<AComponent>();

             }

             protected void operation(int depth) {
                           // 폴더의 이름을 출력함

                           for (int i = 0; i < depth; i++)                                    

                                        System.out.print("-");

                           System.out.println("+" + super.getName());

                           // 해당 폴더안의 자식들을 출력함
                          
for (AComponent c : this.componentList)

                                        c.operation(depth + 2);

             }

             protected void add(AComponent component) {

                           componentList.add(component);

             }

             protected void remove(AComponent component) {

                           componentList.remove(component);

             }

---------------------------------------------------------------------------

public class Client {

             public static void main(String[] args) {

                           Folder root = new Folder("ROOT");

                           root.add(new File("a"));

                           root.add(new File("b"));

                          

                           Folder sub1 = new Folder("SUB1");

                           sub1.add(new File("c"));

                           sub1.add(new File("d"));

                           root.add(sub1);

                          

                           root.add(new File("e"));

                          

                           root.operation(1);

             }

---------------------------------------------------------------------------

[실행결과]

-+ROOT

--- a

--- b

---+SUB1

----- c

----- d
--- e

Posted by 파이팅야
,

abstract factory pattern

Pattern 2008. 4. 11. 13:23
- 상세화된 서브클래스를 정의하지 않고도 서로 관련성이 있거나 독립적인 여러 객체의 군을 생성하기 위한 인터페이스를 제공한다.

- ‘여러 객체의 군의 클래스가 무엇인지 구체적으로 알 필요 없이 해당하는 객체를 생성할 수 있는 인터페이스를 제공한다.

- Abstract Factory Pattern provides a way to encapsulate a group of individual factories that have a common theme

사용자 삽입 이미지
- 소스내용

public abstract class ThemeFactory

             abstract IFontStyle createFontStyle();

             abstract IFontSize createFontSize();

------------------------------------------------------------------------

public class ThemeA extends ThemeFactory

             IFontStyle createFontStyle() {

                           return new Bold();

             }

             IFontSize createFontSize() {

                           Return new Size8();

             }

------------------------------------------------------------------------

public class ThemeB extends ThemeFactory

             @Override

             IFontStyle createFontStyle() {

                           return new Underline();

             }

             @Override

             IFontSize createFontSize() {

                           return new Size10();

             }

------------------------------------------------------------------------

public interface IFontStyle {

             public String getStyle(); }

------------------------------------------------------------------------

public class Bold implements IFontStyle

             public String getStyle() {

                           return "Bold";

             }

------------------------------------------------------------------------

public class Underline implements IFontStyle

             public String getStyle() {

                           return "Underline";

             }

------------------------------------------------------------------------

public interface IFontSize

             public String  getSize();

------------------------------------------------------------------------

public class Size8 implements IFontSize

             @Override

             public String getSize() {

                           return "8pt";

             }

------------------------------------------------------------------------

public class Size9 implements IFontSize

             public String getSize() {

                           return "9pt";

             }

------------------------------------------------------------------------

public class ClientNotePad

             private IFontSize fontSize;

             private IFontStyle fontStyle;

             public ClientNotePad(ThemeFactory themeFactory) {

                           this.fontSize = themeFactory.createFontSize();

                           this.fontStyle = themeFactory.createFontStyle();

             }

             public void print() {

                           System.out.println("FontStyle[" + this.fontStyle.getStyle() + "]");         // [Bold] or [Underline]

                           System.out.println("FontSize[" + this.fontSize.getSize() + "]");                           // [8pt] or [9pt]

             }

             public static void main(String[] args) {

                           System.out.println("ThemeA");

                           ClientNotePad testThemeA = new ClientNotePad(new ThemeA());

                           testThemeA.print();

                          

                           System.out.println("ThemeB");

                           ClientNotePad testThemeB = new ClientNotePad(new ThemeB());

                           testThemeB.print();

             }


  • 응용
    • Factory 객체를 하나만 생성및 유지하는 방법
      • 개요 : ThemeA와 ThemeB중 어느 하나의 객체만 생성해서 사용하면 되고, 이 객체는 전체 프로그램에서 두 개 이상 존재할 필요가 없고, 특정 객체를 하나만 생성하게 명백히 보장하고 싶을 경우 방법
      • 방법 : Singleton Pattern을 사용한다. ClientNotePad부분을 Singleton으로 만들면 소스상에서 분기해서 ThemeA와 ThemeB중에 하나를 생성되도록 변경해야한다. 그러면 추후 ThemeC를 추가할때 소스를 수정해야 하므로 ThemeFactory에 abstract createInstance 메소드를 넣고, ThemeA와 ThemeB에서 각각 createInstalce()를 구현하게 하면 추후 소스수정이 없다.
    • Theme가 추가될때마다 Factory의 자식 클래스를 생성하지 않는 방법
      • 개요 : Theme가 늘어날 때마다 ThemeA및 ThemeB와 같은 클래스들을 구현해야하는 불편을 줄이고 싶을때
      • 방법 : IFontStyle및 IFontSize에 abstract clone()를 넣고 각각의 Bold, Underline, Size8, Size9에서 객체를 복사하는 clone()를 구현하고 ThemeFactory의 생성자에서 IFontStyle과 IFontSize를 받도록 구현하고, ClientNotePad에서 Bold bold; Size8 size8; new ThemeFactory(bold, size8)의 형식과 같이 호출한다. reflection을 써도 될것 같다.
  • 기타
    • ThemeFactory에는 생산해야하는 종류(FontStyle, FontSize)가 abstract method나 virture method로 선언되어 있어야 한다.

Posted by 파이팅야
,