'Design Patterns'에 해당되는 글 24건

  1. 2012.10.29 Decorator 패턴에 대한 생각 정리 (1)
  2. 2012.08.01 싱글톤과 상태 값
  3. 2012.07.05 Template method pattern
  4. 2012.07.04 Strategy pattern
  5. 2012.07.03 State pattern
  6. 2012.06.27 Observer pattern
  7. 2012.06.20 Memento pattern
  8. 2012.06.19 Mediator pattern
  9. 2012.06.18 Iterator pattern
  10. 2012.06.15 Interpreter pattern

안녕하세요.

오늘은 Decorator 패턴에 대해 생각이 정리된 부분을 이야기 해볼까 합니다.


Decorator 패턴에 대한 설명은 위의 링크를 따라 들어가서 보시면 될 것 같구요.


Decorator패턴은 굉장히 간단하고 멋져보이는 패턴입니다.

저도 처음 봤을 때 "우와~ 이런방법이 있구나~" 하면서 놀랐죠.


하지만 막상 실전에 어떻게 활용해야할 지 막막하더군요...

그래서 내린 결론은 

디자인 패턴을 이해한다는 것은 단순히 클래스 관계를 이해하는 것뿐만 아니라, 언제 어떤 의도로 이 패턴이 사용될 수 있는지를 이해하는게 더 중요하다.

라는 것 입니다.


많은 책에서 Decorator패턴을 설명할 때에 커피의 가격 계산에 대한 예를 사용하거나, 윈도우에 스크롤뷰와 프레임을 붙이는 등의 상황을 예로 듭니다. 


그런데 아무리 생각해봐도 이러한 상황에 Decorator패턴을 쓰는게 가능한지 잘 모르겠더군요.




먼저, 커피의 경우에는 Decorator패턴이 정말이지 가격 계산에만 쓰일 수 있는 것 같습니다. 즉, 커피 자체에 대해 Decorator패턴을 적용할 수 있는게 아니라, 커피의 가격에 대해서만 적용이 가능하다는 것입니다. (물론, 커피의 가격만 계산하는 프로그램이라면 전혀 문제될 것이 없지만, 커피의 향이나 색 등을 표현하기에는 Decorator 패턴만으로는 부족하다는 것입니다.)


윈도우 예의 경우에는 윈도우에 스크롤을 입힌다는데, 스크롤 뷰라는게 단순히 뷰만 있는게 아니고 윈도우 내의 컨텐츠 움직임에 따라 스크롤의 길이와 위치가 변화하게 되는데 이런 부분까지 다 표현하는게 가능할까...라는 점입니다.

(이를 Decorator패턴으로 설계 가능하다고 생각하시는 분은 저에게 가르침을 주세요~^^)




이렇게 기존의 예에 대한 이해부족으로 실제로 적용 가능한 상황이 어떤게 있을까.. 하고 생각을 해보게 되었습니다.


터치 효과 Touch Effect

제가 생각한 예는 화면을 터치했을 때 특수한 효과가 나는 예입니다. 

화면을 터치하면 진동이 나올 수도 있고, 터치한 주위로 꽃들이 터질 수도 있고, 화면이 깨지는 효과가 나올 수도 있죠.

또 이들 효과가 2개 이상 동시에 발동될 수도 있습니다.


이러한 효과가 한번에 하나만 가능하다면 Strategy 패턴같은 방법으로 구현이 가능하겠죠. 

하지만 동시에 여러가지 효과가 발동되어야 한다면 Strategy패턴으로 구현하기보다는 Decorator패턴을 이용하는게 좋을 것 같습니다. 


먼저 클래스 다이어그램부터 보시죠.




클래스 구조는 전형적인 Decorator패턴의 모습입니다.

이렇게 Decorator패턴을 이용해서 설계를 하면 생길 수 있는 장점에 대해 이야기를 해보죠.


1. 상태 변수를 이용해 프로그래밍하는 것보다 훨씬 코드가 간결해진다.

첫 번째 장점은 상태 변수를 이용해 프로그래밍하는 것보다 코드가 간결해진다는 점입니다.

즉, 터치 효과를 저장하는 int형의 멤버 변수를 만들고 이 멤버 변수에 어떤 효과들이 설정되어있는지 설정값을 담아둘 수 있습니다. 


public static final int TOUCH_EFFECT_FLOWER = 1 << 0;
public static final int TOUCH_EFFECT_CRACK = 1 << 1;
public static final int TOUCH_EFFECT_VIBRATION = 1 << 2;

private int _touchEffects = TOUCH_EFFECT_FLOWER | TOUCH_EFFECT_CRACK;


이렇게 _touchEffects 변수에 터치 효과들을 담아두고 있다가, 사용하는 곳에서 변수를 체크해서 적절한 효과를 발동시키는 겁니다. 

 

public void onTouch(float x, float y) {
    if(_touchEffects & TOUCH_EFFECT_FLOWER == TOUCH_EFFECT_FLOWER) {
        //꽃 효과를 발동한다.
    }

    if(_touchEffects & TOUCH_EFFECT_CRACK == TOUCH_EFFECT_CRACK) {
        //액정이 깨진 효과를 발동한다.
    }

    if(_touchEffects & TOUCH_EFFECT_VIBRATION == TOUCH_EFFECT_VIBRATION) {
        //진동 효과를 발동한다. 
    }
}


이렇게 사용하는 터치 효과를 발동해야 하는 곳에서 _touchEffects 변수를 체크해서 사용해야 합니다.

이렇게 사용하는 것의 단점이 뭘까요?

솔직히 복잡하게 설계를 하는 것보다 이렇게 쓰는게 훨씬 빨리 코딩할 수 있는 방법아닐까요?


지금 보여진 코드만 보면 그렇습니다.

하지만,, _touchEffects라는 변수는 여기에서만 사용되지 않을 수도 있습니다.

다른 메서드에서도 저런 분기문을 똑같이 사용할 수 있습니다.

또 효과가 하나씩 늘어날 때마다 _touchEffects 변수를 사용하는 곳의 코드를 또 추가적으로 작성해야 하구요.

그렇게 _touchEffects를 사용하는 메서드가 늘어날수록 코드는 더욱더 복잡해지고, 수정을 위해 많은 시간과 노력을 요할 수 있습니다.


2. Strategy 패턴을 이용하는 설계보다 클래스 수를 훨씬 줄일 수 있다.

만약 Decorator패턴을 사용하지 않고, Strategy패턴을 이용해 설계를 하면 이 경우에는 훨씬 많은 수의 클래스가 필요할 수 있습니다.

혹시 오해하실까봐 말씀드리는데 Strategy패턴이 Decorator패턴보다 좋지 않다는게 아니라, 지금 제가 말씀드리고 있는 이 상황에서 그렇다는 겁니다.  



먼저 이 상황을 다시 한번 설명 드리자면, 동시에 여러개의 효과가 발동될 수 있습니다.


즉, 꽃 효과와 진동효과가 동시에 발동되거나 진동효과와 액정 깨짐 효과가 동시에 발동될 수도 있습니다.

이를 Strategy패턴으로 구현하려면 TouchEffect인터페이스를 상속받는 FlowerTouchEffect, VibrationTouchEffect, CrackTouchEffect뿐만 아니라 이들을 조합한 FlowerVibrationTouchEffect, FlowerCrackTouchEffect ..등등 많은 수의 서브 클래스가 필요하게 됩니다.


정리

이렇게 수평적인 관계의 여러 기능을 동적으로 결합해야하는 경우에 Decorator패턴이 잘 사용될 수 있을 것 같습니다. 


또 다르게 사용될 수 있는 방법이 생각난다면 다음 번에 포스팅하기로 하죠~^^

저작자 표시 비영리 변경 금지
신고

'Design Patterns > 내 생각' 카테고리의 다른 글

Decorator 패턴에 대한 생각 정리  (1) 2012.10.29
싱글톤과 상태 값  (0) 2012.08.01
Posted by Code-Moon

댓글을 달아 주세요

  1. ㅁㄴㅇㄹ 2012.12.01 22:02 신고 Address Modify/Delete Reply

    잘 보고 갑니다 ^^ Decorator 패턴을 쓰면 switch문을 쓰는 것보다 재사용성하고, 유지보수가

    쉬워지는 장점이 있네요 ㅎㅎ

안녕하세요?

요즘 맨날 영어 공부와 디자인 패턴 공부를 동시에 하기 위해, 영문 위키에 있는 디자인 패턴 번역 작업만 하다가 오랜만에 제 글을 쓰네요^^



오늘은 싱글톤에 대한 제 생각을 정리해보려 합니다. (오늘 코드 수정 작업을 하다가 든 생각입니다.^^)


저는 원래 싱글톤을 자주 사용하면서도 남용하지 않으려 노력하고 있었습니다.

왜냐하면 일각에서는 싱글톤을 안티패턴의 일종으로 간주하기 때문이죠. 



분명히 써보면 굉장히 편리한 디자인 패턴인데도 불구하고, 너무나 편리한 나머지 아무곳에서나 마구마구 쓸 수 있는 만능 클래스가 될 수 있다는 우려때문에, 싱글톤을 사용하는데에 있어 조심스럽더라구요.

그러다가 cocos2d-x를 접하게 되었는데, 여기에서 싱글톤을 꽤나 잘 쓰고 있는 것 같았습니다.


일단 cocos2d는 너무나 잘 알려진 오픈소스 게임 엔진인데요, 굉장히 유명하고 많이 사용되는만큼 코드에 대한 저의 신뢰성도 높아지더군요. 그리고 실제로 오픈 소스 엔진들을 분석해보면 꽤나 좋은 설계 요소들이 많습니다.



어쨌든 이번에 프로젝트를 진행하면서 몇몇 싱글톤 클래스를 만들 필요가 있었습니다.

일단 그 클래스들을 싱글톤으로 설계한 것은 꽤 잘 된 선택이라고 생각합니다.(어쩌면 더 좋은 방법이 있었을 수도 있지만...)


그런데 문제는 싱글톤 클래스에 상태 변수를 넣으면서부터 시작되었습니다. 처음 구현을 할 때에는 그 클래스에 적당한 상태 변수라고 생각했습니다. 이 변수 값은 setter를 통해 외부에서 수정될 수 있고, getter를 통해 외부에서 값을 확인할 수 있습니다.


싱글톤 클래스에 상태변수를 넣으면 왜 문제가 될까요?



싱글톤은 모든 클래스에서 접근 가능한 클래스이자 객체입니다. 다시 말하면, 모든 클래스에서 싱글톤의 상태값을 변화시킬 수 있다는 것이죠.

이러한 특징이 처음 구현을 할 때에는 굉장히 편하게 느껴집니다. (저도 실제로 그러했습니다. 그냥 원하는 클래스에서 싱글톤에 접근해서 상태변수를 마음 껏 바꾸면 되죠.ㅎ)


예를들어, A 클래스에서 싱글톤의 상태 변수를 변화시키고, B 클래스에서는 싱글톤의 상태 변수에 따라 어떤 일을 수행하고, C 클래스에서는 싱글톤의 상태 변수에 따라 싱글톤의 상태 변수를 다른 값으로 변화시키는 등의 코드를 작성할 수 있습니다.


그런데, 이렇게 싱글톤 객체의 상태를 이용한 코드를 작성하고나서 얼마 뒤에 그 코드에 기능을 추가하던지, 기능을 변경해야하는 경우가 있다면 굉장히 머리 아픈 일이 생길 수 있습니다.


위의 예에서 B클래스는 싱글톤 상태 변수의 값에 따라 하는 일이 결정되는데, 그 싱글톤의 상태 변수는 모든 클래스에서 값을 바꿀 수 있습니다.  그래서 B클래스에서 어떤 일이 수행될지를 확인하기 위해서는 싱글톤의 상태 변수를 변화시키는 모든 코드를 살펴봐야합니다. 

싱글톤은 너무나도 자유로운 클래스이기에 어디에서 값이 어떻게 바뀌었는지 정확히 추측해내기가 쉽지 않습니다. (물론, 정말 작은 시스템이라면 문제 없을 수도 있지만, 보통의 프로젝트는 결코 작은 시스템으로 끝나지 않죠?ㅎㅎㅎ)



그래서 오늘 내린 결론은, 싱글톤을 사용할 때에는 외부에서 접근 가능한 상태 변수를 왠만해서는 사용 안하는게 미래를 위해 좋다는 것입니다.


저작자 표시 비영리 변경 금지
신고

'Design Patterns > 내 생각' 카테고리의 다른 글

Decorator 패턴에 대한 생각 정리  (1) 2012.10.29
싱글톤과 상태 값  (0) 2012.08.01
Posted by Code-Moon

댓글을 달아 주세요

먼저 이 글은 영문 위키의 글을 번역한 글임을 알려드립니다.

영어실력이 부족한 관계로 오역이 있을 수도 있습니다.

원문주소 : http://en.wikipedia.org/wiki/Template_method_pattern



Behavioral - Template method pattern

소프트웨어 공학(software engineering)에서 template method pattern디자인 패턴(design pattern) 중 하나이다. 행위적 패턴(behavioral pattern) 중 하나이고, C++ templates와는 무관하다.

도입 Introduction

template method 는 특정 알고리즘프로그램 스켈레톤(program skeleton)을 정의한다. 하나 이상의 알고리즘 단계들이 하위 클래스(서브 클래스)에서 재구현(overriden)될 수 있는데, 이 때 중요한 뼈대가 되는 알고리즘은 그대로 유지한체 다른 동작을 할수 있도록 한다.


객체 지향 프로그래밍에서 한 클래스는 특정 알고리즘 설계(algorithm design)의 기본적인 단계들을 제공하도록 만들어진다. 이러한 단계들은 추상메서드(abstract methods)를 사용해서 구현된다. 서브클래스에서는 추상 메서드를 실제로 동작하게 끔 구현한다. 뼈대에 해당하는 알고리즘은 유지한채로 서브 클래스에서 각 단계들의 구현만 달라지게 된다.


template method 패턴은 의미(semactics)에 해당하는 큰 그림과 세부 구현, 그리고 일련의 메서드들을 다룬다. 이런 큰 그림이 추상 메서드와 비추상(non-abstract) 메서드를 호출한다. 비추상 메서드는 template method에 의해 전적으로 처리되지만, 서브 클래스에서 구현되는 추상 메서드는 이 패턴의 힘과 자유도를 제공한다. 추상 메서드의 일부 또는 전체는 서브 클래스에서 구현이 되는데, 서브 클래스를 작성하는 사람이 더 큰 의미론적으로는 변화를 최소화시킨 채 특정 행동을 할 수 있도록 해준다. 


template method 패턴은 자주 사용된다. 한 메서드가 오직 하나의 추상 메서드를 호출하는 경우는 정말 최소한으로 template method를 사용한 케이스라 볼 수 있다. 어떤 개발자가 다형성(polymorphic)을 전적으로 사용하고 있다면, 이 디자인 패턴은 꽤나 자연스러운 결과이다. template method는 지금 당장 존재하는 값을 소프트웨어에 추가하기 위해 사용되거나 미래에 더 강화된 기능을 위해 사용된다. 


template method 패턴은 Non-Virtual Interface(NVI) 패턴과 밀접한 관련이 있다. NVI 패턴은 비추상 메서드가 추상 메서드를 호출하는 것의 장점을 잘 알고 있다. NVI 패턴은 아주 작은 소프트웨어 생산과 런타임 비용을 들게 할 수 있다. 많은 상업적 소프트웨어 프레임웍(software frameworks)에서는 NVI 패턴을 채용하고 있다.


Template method 패턴은 Adapter Pattern에서 하듯이 GRASP를 구현한다. 다른 점은 Adapter는 여러 오퍼레이션에게 같은 인터페이스를 제공하지만, Template Method는 오직 하나에게만 제공한다는 점이다.

구조 Structure



사용법 Usage

Template method는 다음과 같은 경우에 사용된다.

  • 변할 수 있는 행위에 대한 구현은 서브 클래스에서 메서드 오버라이딩(method overriding)을 통해 하도록 한다.
  • 코드의 중복 제거 : 추상 클래스의 알고리즘에서 일반적인 흐름 구조는 한번만 구현되고, 필요한 변화는 각 서브클래스에서 구현된다.
  • 어떤 지점에서 서브 클래싱(subclassing)이 가능한지를 조절할 수 있다. 흐름에 대해 근본적인 부분부터 다 바꿔버리는 단순한 다형성 오버라이드와는 반대로, 흐름의 일부에 대해서만 변화를 허용한다.


template 패턴을 사용한 애플리케이션의 결과인 조절 구조(inversion of control)헐리웃 원리(Hollywood Principle, "날 부르지마, 내가 널 부를테니..") 같다고 언급된다. 이 원리를 이용하면 부모 클래스에 있는 template method는 서브클래스의 메서드를 필요할 때 호출함으로써 전반적인 프로세스를 관리한다.  다음의 자바 예를 보면 알 수 있다. 


예 Example

/**
 * An abstract class that is 
 * common to several games in
 * which players play against 
 * the others, but only one is
 * playing at a given time.
 */
 
abstract class Game {
 
    protected int playersCount;
    abstract void initializeGame();
    abstract void makePlay(int player);
    abstract boolean endOfGame();
    abstract void printWinner();
 
    /* A template method : */
    public final void playOneGame(int playersCount) {
        this.playersCount = playersCount;
        initializeGame();
        int j = 0;
        while (!endOfGame()) {
            makePlay(j);
            j = (j + 1) % playersCount;
        }
        printWinner();
    }
}
 
//Now we can extend this class in order 
//to implement actual games:
 
class Monopoly extends Game {
 
    /* Implementation of necessary concrete methods */
    void initializeGame() {
        // Initialize players
        // Initialize money
    }
    void makePlay(int player) {
        // Process one turn of player
    }
    boolean endOfGame() {
        // Return true if game is over 
        // according to Monopoly rules
    }
    void printWinner() {
        // Display who won
    }
    /* Specific declarations for the Monopoly game. */
 
    // ...
}
 
class Chess extends Game {
 
    /* Implementation of necessary concrete methods */
    void initializeGame() {
        // Initialize players
        // Put the pieces on the board
    }
    void makePlay(int player) {
        // Process a turn for the player
    }
    boolean endOfGame() {
        // Return true if in Checkmate or 
        // Stalemate has been reached
    }
    void printWinner() {
        // Display the winning player
    }
    /* Specific declarations for the chess game. */
 
    // ...
}


저작자 표시 비영리 변경 금지
신고

'Design Patterns > 영문 위키(Wikipedia)' 카테고리의 다른 글

Template method pattern  (0) 2012.07.05
Strategy pattern  (0) 2012.07.04
State pattern  (0) 2012.07.03
Observer pattern  (0) 2012.06.27
Memento pattern  (0) 2012.06.20
Mediator pattern  (0) 2012.06.19
Posted by Code-Moon

댓글을 달아 주세요

먼저 이 글은 영문 위키의 글을 번역한 글임을 알려드립니다.
영어 실력이 부족한 관계로 오역이 있을 수도 있습니다.

원문 주소 : http://en.wikipedia.org/wiki/Strategy_pattern



Behavioral - Strategy Pattern


컴퓨터 프로그래밍(computer programming)에서 policy pattern이라고도 알려져 있는 strategy pattern은 런타임 시에 알고리즘(algorithms)을 선택할 수 있는 특별한 디자인 패턴(software design pattern) 중 하나이다. 형식적으로 말하면 strategy 패턴은 알고리즘 군(family)을 정의하고, 각각을 캡슐화해서 서로 바꿔가며 쓸 수 있게 한다. strategy는 그를 사용하는 클라이언트 코드로부터 알고리즘을 독립적으로 바꿀 수 있게 해준다. 


예를 들어, 어떤 데이터의 유효성을 체크하는 클래스가 있는데, 이 클래스는 데이터의 타입이나 사용자의 선택 등의 특정 인자에 따라 유효성 체크 알고리즘을 선택하기 위해 strategy 패턴을 사용할 수 있다. 이러한 인자는 실제 그 상황이 되기 전까지는 아무 것도 모르고, 그 상황마다 유효성 체크 알고리즘이 완전히 달라질 수도 있다. 

유효성을 체크하는 객체로부터 분리되어 캡슐화되는 유효성 체크 전략(strategies)은 시스템의 다른 영역에서 코드 중복없이 사용될 수 있다 .


프로그래밍 언어(programming language)에서 필수적인 요소는 어떤 자료 구조 내의 코드에 대한 참조를 가지고 있다가 필요할 때 사용하는 것이다. 이는 function pointer, first-class function, 객체지향 프로그래밍 언어에서 클래스나 클래스 인스턴스, 또는 reflection을 통한 언어 구현의 내부 코드에 대한 접근같은 메커니즘으로 성취할 수 있는 부분이다. 

구조 Structure



예 Example

다음은 Java의 한 예이다.


// The classes that implement a concrete strategy should implement this.
// The Context class uses this to call the concrete strategy.
interface Strategy {
    int execute(int a, int b); 
}
 
// Implements the algorithm using the strategy interface
class ConcreteStrategyAdd implements Strategy {
 
    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyAdd's execute()");
        return a + b;  // Do an addition with a and b
    }
}
 
class ConcreteStrategySubtract implements Strategy {
 
    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategySubtract's execute()");
        return a - b;  // Do a subtraction with a and b
    }
}
 
class ConcreteStrategyMultiply implements Strategy {
 
    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyMultiply's execute()");
        return a * b;   // Do a multiplication with a and b
    }    
}
 
// Configured with a ConcreteStrategy object and maintains a reference to a Strategy object
class Context {
 
    private Strategy strategy;
 
    // Constructor
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
 
    public int executeStrategy(int a, int b) {
        return strategy.execute(a, b);
    }
}
 
// Test application
class StrategyExample {
 
    public static void main(String[] args) {
 
        Context context;
 
        // Three contexts following different strategies
        context = new Context(new ConcreteStrategyAdd());
        int resultA = context.executeStrategy(3,4);
 
        context = new Context(new ConcreteStrategySubtract());
        int resultB = context.executeStrategy(3,4);
 
        context = new Context(new ConcreteStrategyMultiply());
        int resultC = context.executeStrategy(3,4);
    }
}

Strategy versus Bridge

strategy 패턴의 UML 클래스 다이어그램은 Bridge 패턴의 다이어그램과 같다. 하지만 이 둘은 의도(목적, intent)가 다르다. strategy 패턴은 행위(behavior)와 관련있지만, Bridge 패턴은 구조(structure)와 관련있다. 

context와 strategy간의 커플링이 Bridge패턴의 abstraction와 implementation간의 커플링보다 더 강하다.

Strategy and open/closed principle

strategy 패턴에 따르면, 클래스의 행위는 상속되는 것보다는 인터페이스를 이용해서 캡슐화되어야 한다. 예를들어 car클래스를 생각해보자. car의 두 가지 가능한 기능은 정지(brake)와 가속(accelerate)이다. 


정지와 가속은 자동차 모델에 따라 자주 바뀔 수 있는 부분이기 때문에, 이를 구현하기 위한 일반적인 접근은 상속이다. 이 방법은 중대한 단점이 있다. 가속과 정지는 새로운 자동차 모델마다 새로 정의되어야 한다. 이는 자동차 모델의 개수가 늘어날 수록 관리해야하는 부분이 많아지고, 모델간의 코드 중복되 많아진다. 게다가 각각의 모델에 코드를 추가하지 않기도 어렵다. 


strategy 패턴에서는 상속 대신에 집합(aggregation)을 이용한다. strategy패턴에서 행위(behaviors)는 여러 인터페이스와 그 인터페이스를 구현하는 클래스들로 정의된다. 각 클래스는 이 인터페이스를 캡슐화한다. 이는 행위와 그 행위를 사용하는 클래스 사이의 커플링을 감소시킨다. 행위는 그 행위를 사용하는 클래스의 변화없이 바뀔 수 있고, 심한 코드 변화없이도 행위를 서로 바꿀 수 있다.  행위는 디자인(설계) 시점 뿐만 아니라 런타임 시에도 바뀔 수 있다. 예를 들어, car 객체의 정지 행위는 brakeBehavior 멤버를 다음과 같이 바꿈으로써 BrakeWithABS()에서 Brake()으로 바뀔 수 있다.

brakeBehavior = new Brake();


이는 설계에서 엄청난 유연성을 제공하고, "클래스는 확장에 열려있어야 하고 수정에는 닫혀있어야 한다"고 말하는 Open/Closed Princicle(OCP)와 잘 어울린다.

저작자 표시 비영리 변경 금지
신고

'Design Patterns > 영문 위키(Wikipedia)' 카테고리의 다른 글

Template method pattern  (0) 2012.07.05
Strategy pattern  (0) 2012.07.04
State pattern  (0) 2012.07.03
Observer pattern  (0) 2012.06.27
Memento pattern  (0) 2012.06.20
Mediator pattern  (0) 2012.06.19
Posted by Code-Moon

댓글을 달아 주세요

먼저 이 글은 영문 위키의 글을 번역한 글임을 알려드립니다.

영어 실력이 부족한 관계로 오역이 있을 수도 있습니다.

원문 주소 : http://en.wikipedia.org/wiki/State_pattern



Behavioral - State Pattern

Strategy Pattern과 매우 닮은 state 패턴행위적 디자인 패턴(behavioral software design pattern)인데, 상태를 위한 객체 패턴(objects for states pattern)이라고도 알려져 있다. 이 패턴은 어떤 객체의 상태를 나타내기 위해 컴퓨터 프로그래밍(computer programming)에서 사용된다. 이는 런타임시에 어떤 객체를 부분적으로 변화시키기에 명확한 방법이다. 

구조 Structure



예 Example

의사 코드 Pseudocode

예를들어 그림을 그리는 프로그램을 생각해보자. 이 프로그램에는 마우스 커서가 있는데, 이 커서는 특정 시점에 여러 도구 중 하나로 동작할 수 있다. 커서 객체를 각 상황에 맞게 바꾸는 것 대신에, 커서가 내부 상태를 가지고 있고, 이 상태가 현재 사용하고 있는 도구를 나타낸다. 도구에 의존적인 메서드가 호출될때 (예를들면 마우스 클릭), 이 메서드 호출은 커서의 상태에 전달이 된다. 

각 도구는 하나의 상태를 나타낸다. 추상 상태 클래스는 AbstractTool이다. 


 class AbstractTool is
     function moveTo(point) is
         input:  the location point the mouse moved to
         (this function must be implemented by subclasses)
 
     function mouseDown(point) is
         input:  the location point the mouse is at
         (this function must be implemented by subclasses)
 
     function mouseUp(point) is
         input:  the location point the mouse is at
         (this function must be implemented by subclasses)

이 정의에 따르면, 각 도구는 마우스 커서의 움직임과 클릭이나 드래그에 대한 시작점과 끝점에 대해서도 처리해야 한다.
베이스(추상) 클래스를 이용해서 간단한 펜 도구와 선택 도구를 다음과 같이 만들 수 있다.


subclass PenTool of AbstractTool is
     last_mouse_position := invalid
     mouse_button := up
 
     function moveTo(point) is
         input:  the location point the mouse moved to
         if mouse_button = down
             (draw a line from the last_mouse_position to point)
             last_mouse_position := point
 
     function mouseDown(point) is
         input:  the location point the mouse is at
         mouse_button := down
         last_mouse_position := point
 
     function mouseUp(point) is
         input:  the location point the mouse is at
         mouse_button := up  

 subclass SelectionTool of AbstractTool is
     selection_start := invalid
     mouse_button := up
 
     function moveTo(point) is
         input:  the location point the mouse moved to
         if mouse_button = down
             (select the rectangle between selection_start and point)
 
     function mouseDown(point) is
         input:  the location point the mouse is at
         mouse_button := down
         selection_start := point
 
     function mouseUp(point) is
         input:  the location point the mouse is at
         mouse_button := up

이 예에서 context를 위한 클래스는 Cursor라 불린다. 추상 상태 클래스(여기에서는 AbstractTool)의 메서드들은 context 안에서도 모두 구현된다. context클래스에서 이 메서드들은 현재 상태(Cursor클래스에서 current_tool로 표시)의 관련 메서드를 호출한다.


class Cursor is
     current_tool := new PenTool
 
     function moveTo(point) is
         input:  the location point the mouse moved to
         current_tool.moveTo(point)
 
     function mouseDown(point) is
         input:  the location point the mouse is at
         current_tool.mouseDown(point)
 
     function mouseUp(point) is
         input:  the location point the mouse is at
         current_tool.mouseUp(point)
 
     function usePenTool() is
         current_tool := new PenTool
 
     function useSelectionTool() is
         current_tool := new SelectionTool

Cursor객체가 어떻게 다른 시점에 PenTool과 SelectionTool로 동작할 수 있는 지에 주목하자. Cursor는 어떤 툴이 활성화되어 있든지 상관없이 적절한 메서드를 호출한다. 이것이 state pattern의 정수(essence)이다. 여기에서 우리는 단순한 상속만을 이용한 PenCursor와 SelectCursor 클래스를 만들어서 상태와 객체를 결합시킬 수도 있었다. 하지만 Cursor는 새로운 툴이 선택될 때마다 비싸거나 새로운 객체로 복사하는데 우아하지 않은 데이터를 옮길 수도 있다. 


Java

상태 인터페이스와 두개의 구현. 상태의 메서드는 context객체에 대한 참조를 가지고 있고, 상태를 바꿀 수도 있다.

interface State {
        void writeName(StateContext stateContext, String name);
}
 
class StateA implements State {
        public void writeName(StateContext stateContext, String name) {
                System.out.println(name.toLowerCase());
                stateContext.setState(new StateB());
        }
}
 
class StateB implements State {
        private int count=0;
        public void writeName(StateContext stateContext, String name){
                System.out.println(name.toUpperCase());
                // change state after StateB's writeName() gets invoked twice
                if(++count>1) {
                        stateContext.setState(new StateA());
                }
        }
}

context 클래스는 상태 변수를 가지고 있는데, 이 상태 변수는 초기 상태에서 인스턴스화된다. 여기에서는 StateA가 초기 상태이다. 이 메서드에서 상태 객체의 관련된 메서드를 사용하는 것을 볼 수 있다.

public class StateContext {
        private State myState;
        public StateContext() {
                setState(new StateA());
        }
 
        // normally only called by classes implementing the State interface
        public void setState(State newState) {
                this.myState = newState;
        }
 
        public void writeName(String name) {
                this.myState.writeName(this, name);
        }
}

그리고 다음과 같이 사용한다.

public class TestClientState {
        public static void main(String[] args) {
                StateContext sc = new StateContext();
                sc.writeName("Monday");
                sc.writeName("Tuesday");
                sc.writeName("Wednesday");
                sc.writeName("Thursday");
                sc.writeName("Saturday");
                sc.writeName("Sunday");
        }
}

위의 코드에서 TestClientState클래스의 main()메서드의 결과는 다음과 같다.

monday
TUESDAY
WEDNESDAY
thursday
SATURDAY
SUNDAY
저작자 표시 비영리 변경 금지
신고

'Design Patterns > 영문 위키(Wikipedia)' 카테고리의 다른 글

Template method pattern  (0) 2012.07.05
Strategy pattern  (0) 2012.07.04
State pattern  (0) 2012.07.03
Observer pattern  (0) 2012.06.27
Memento pattern  (0) 2012.06.20
Mediator pattern  (0) 2012.06.19
Posted by Code-Moon

댓글을 달아 주세요

먼저 이 글은 영문 위키의 글을 번역한 글임을 알려드립니다.

영어 실력이 부족한 관계로 오역이 있을 수도 있습니다.

원문 주소 : http://en.wikipedia.org/wiki/Observer_pattern



Behavioral - Observer pattern

옵저버(observer) 패턴은 subject라 불리는 객체(object)가 observer라 불리는 객체들의 리스트를 관리하고, 상태변화가 있으면 알아서 옵저버 객체들에게 알려주는(종종 옵저버의 메서드 methods를 호출함으로써 알려주는) 디자인 패턴(software design pattern)이다. 

이 패턴은 주로 분산된 이벤트 처리(event handling) 시스템에서 사용된다. 또한 옵저버는 MVC 패턴의 중요한 부분이기도 하다.

사실, 옵저버는 Smalltalk의 MVC 기반 UI 프레임웍에서 가장 먼저 구현되었다.


관련된 패턴들 : Publish-subscribe pattern, mediator, singleton

구조 Structure


정의 Definition

옵저버 패턴의 정수(essence)는 다음과 같다.

객체 사이에 일대다(one-to-many) 관계를 정의함으로써, 한 객체의 상태가 변경되었을 때 의존하는(dependents) 객체들에게 자동으로 알려주고 업데이트하도록 하기 위함이다.

예 Example

아래는 키보드 입력을 받아서 한줄 마다 이벤트로 처리하는 예이다. 이 예는 java.util.Observerjava.util.Observable 이 두개의 라이브러리 클래스를 사용해서 만들었다. System.in 으로부터 문자열이 들어오면 notifyObservers()메서드가 호출되고, 그러면 모든 옵저버들의 update메서드를 호출함으로써(이 예에서는 ResponseHandler.update메서드) 이벤트의 발생을 알린다. 


MyApp.java파일에 코드를 실행시킬 수 있는 main()메서드가 있다.


/* File Name : EventSource.java */
package org.wikipedia.obs;
 
import java.util.Observable;          //Observable is here
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class EventSource extends Observable implements Runnable {
    public void run() {
        try {
            final InputStreamReader isr = new InputStreamReader(System.in);
            final BufferedReader br = new BufferedReader(isr);
            while (true) {
                String response = br.readLine();
                setChanged();
                notifyObservers(response);
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

/* File Name: ResponseHandler.java */
 
package org.wikipedia.obs;
 
import java.util.Observable;
import java.util.Observer;  /* this is Event Handler */
 
public class ResponseHandler implements Observer {
    private String resp;
    public void update(Observable obj, Object arg) {
        if (arg instanceof String) {
            resp = (String) arg;
            System.out.println("\nReceived Response: " + resp );
        }
    }
}

/* Filename : MyApp.java */
/* This is the main program */
 
package org.wikipedia.obs;
 
public class MyApp {
    public static void main(String[] args) {
        System.out.println("Enter Text >");
 
        // create an event source - reads from stdin
        final EventSource eventSource = new EventSource();
 
        // create an observer
        final ResponseHandler responseHandler = new ResponseHandler();
 
        // subscribe the observer to the event source
        eventSource.addObserver(responseHandler);
 
        // starts the event thread
        Thread thread = new Thread(eventSource);
        thread.start();
    }
}

구현 Implements

옵저버 패턴은 거의 대부분의 GUI 툴킷을 포함한 많은 프로그래밍 라이브러리(programming libraries)와 시스템에서 구현되어 있다. 아래와 같은 주목할만한 구현들이 있다.

ActionScript


C


C++


Objective-C


C#


ColdFusion


Delphi


Java

  • java.util.Observer 클래스에서 간단한 옵저버 구현을 제공하고 있다.
  • 전형적으로 자바에서 이벤트는 callback 패턴으로 구현되어 있다. : 한 부분은 공통 인터페이스를 제공하고, 다른 부분은 그 인터페이스를 구현하고, 또 다른 부분은 인터페이스에 대한 레퍼런스를 가지고 있다가 이벤트를 발생시킨다. 


JavaScript

  • EventDispatcher singleton
  • DevShop
  • jQuery에서 이벤트 핸들러를 만들기 위해 '.on()'을 쓰고, 이벤트를 발생시키기 위해 '.trigger()'를 쓰고, 이벤트 핸들러를 제거하기 위해'off()'를 사용하도록 되어 있는데, 이 것이 옵저버 패턴을 구현한 부분이다. jQuery에서는 실제 메모리에 DOM 요소를 올려서 사용하는데, 이벤트 핸들러는 DOM구조에 붙였다가 DOM의 해당 요소가 삭제되면 자동적으로 이벤트도 삭제된다. 더 많이 알고 싶다면 jQuery Event Model 슬라이드 쇼를 봐라.


Lisp


Perl


PHP


Python


Ruby

  • Observer - 루비 표준 라이브러리에 있다.

Other/Misc


저작자 표시 비영리 변경 금지
신고

'Design Patterns > 영문 위키(Wikipedia)' 카테고리의 다른 글

Strategy pattern  (0) 2012.07.04
State pattern  (0) 2012.07.03
Observer pattern  (0) 2012.06.27
Memento pattern  (0) 2012.06.20
Mediator pattern  (0) 2012.06.19
Iterator pattern  (0) 2012.06.18
Posted by Code-Moon

댓글을 달아 주세요

먼저 이 글은 영문 위키의 글은 번역한 글임을 알려드립니다.

영어 실력이 부족한 관계로 오역이 있을 수도 있습니다.

원문 주소 : http://en.wikipedia.org/wiki/Memento_pattern



Behavioral - Memento pattern



memento 패턴은 객체의 이전 상태를 저장하는 방법을 제공하는 소프트웨어 디자인 패턴(software design pattern)이다. (롤백을 통한 취소(undo)와 같은 예가 있다.)


memento 패턴은 originator(창작자, 시조)와 caretaker(경비원, 관리인)라는 두개의 객체로 구현된다. Originator는 내부 상태(state)를 가지고 있는 객체이다. Caretaker는 originator에게 어떤 동작을 하지만 변화에 대해 취소하고 싶어한다. caretaker는 먼저 originator에게 memento객체를 요청한다. 그러면 caretaker가 어떤 일을 하려고했던지 상관없이 그 동작을 수행한다. 동작이 일어나기 전 상태로 되돌리기 위해 caretaker는 originator에게 memento객체를 반환한다. memento객체는 불투명한 객체(opaque object)이다. (caretaker는 memento객체를 변경할 수 없기 때문에). 이 패턴을 사용할 때 originator가 다른 객체나 자원(resources)을 변경할 수 있다면 주의를 기울여야 한다.(memento 패턴은 한 특정 객체안에서 동작한다.)


memento 패턴에 대한 전형적인 예에는 pseudorandom number generator 의 씨앗(seed, 랜덤 숫자를 생성할 때 사용하는 일종의 key라고 생각하면 되겠네요.)과 finite state machine의 상태가 있다.

예 Example

아래의 예는 Memento 패턴의 "undo"사용법을 묘사하고 있는 Java 프로그램이다.

import java.util.List;
import java.util.ArrayList;
class Originator {
    private String state;
    // The class could also contain additional data that is not part of the
    // state saved in the memento.
 
    public void set(String state) {
        System.out.println("Originator: Setting state to " + state);
        this.state = state;
    }
 
    public Memento saveToMemento() {
        System.out.println("Originator: Saving to Memento.");
        return new Memento(state);
    }
 
    public void restoreFromMemento(Memento memento) {
        state = memento.getSavedState();
        System.out.println("Originator: State after restoring from Memento: " + state);
    }
 
    public static class Memento {
        private final String state;
 
        public Memento(String stateToSave) {
            state = stateToSave;
        }
 
        public String getSavedState() {
            return state;
        }
    }
}
 
class Caretaker {
    public static void main(String[] args) {
        List savedStates = new ArrayList();
 
        Originator originator = new Originator();
        originator.set("State1");
        originator.set("State2");
        savedStates.add(originator.saveToMemento());
        originator.set("State3");
        // We can request multiple mementos, and choose which one to roll back to.
        savedStates.add(originator.saveToMemento());
        originator.set("State4");
 
        originator.restoreFromMemento(savedStates.get(1));   
    }
}



결과는 아래와 같다.

Originator: Setting state to State1
Originator: Setting state to State2
Originator: Saving to Memento.
Originator: Setting state to State3
Originator: Saving to Memento.
Originator: Setting state to State4
Originator: State after restoring from Memento: State3



이 예에서는 상태를 표현하기 위해 String 클래스를 사용하고 있다.(이는 자바에서 기본적으로 immutable type(변하지 않는 타입)이다.) 실제 시나리오에서 상태는 대게는 특정 객체가 되어야 한다. 그래서 memento 객체에 넣기 전에 상태객체는 복제해서 넣어야한다.

 private Memento(State state)
        {
            //state has to be cloned before returning the 
            //memento, or successive calls to get Memento
            //return a reference to the same object
            this.mementoState = state.clone();
 
        }


저작자 표시 비영리 변경 금지
신고

'Design Patterns > 영문 위키(Wikipedia)' 카테고리의 다른 글

State pattern  (0) 2012.07.03
Observer pattern  (0) 2012.06.27
Memento pattern  (0) 2012.06.20
Mediator pattern  (0) 2012.06.19
Iterator pattern  (0) 2012.06.18
Interpreter pattern  (0) 2012.06.15
Posted by Code-Moon

댓글을 달아 주세요

먼저 이 글은 영문 위키의 글을 번역한 글 임을 알려드립니다.

영어 실력이 부족한 관계로 오역이 있을 수도 있습니다.

원문 주소 : http://en.wikipedia.org/wiki/Mediator_pattern



Behavioral - Mediator pattern


mediator pattern은 한 집합의 객체들이 어떻게 상호작용하는지를 캡슐화 한 객체를 정의한다. 이 패턴은 프로그램이 동작하는 행위를 변경할 수 있기 때문에 behavioral pattern으로 간주된다.


보통 한 프로그램은 많은 클래스들(classes)로 만들어 진다. 그래서 논리(logic)계산(computation)이 이런 클래스들 사이에 분산되어 있다. 하지만 더 많은 클래스들이 만들어질수록 클래스들 간의 의사소통(communication) 문제는 더욱 복잡해진다.(특히 유지보수(maintenance)리펙토링(refactoring)을 할 때에는 더욱 더) 이러한 문제는 프로그램을 읽기 힘들게, 그리고 유지보수(maintain)하기 힘들게 만든다. 게다가, 이런 상황에서 약간의 코드 변화라도 다른 일부 클래스들에게 영향을 끼칠 수 있기 때문에 프로그램을 수정하는 게 어려워질 수 있다.


mediator 패턴을 이용하면, 객체간의 의사소통은 mediator객체에 의해 캡슐화 된다. 객체들은 더 이상 직접적으로 의사소통하지 않고, mediator를 통해서만 의사소통을 한다. 이렇게 함으로써 의사소통하는 객체들간의 의존도(dependencies)를 낮추고 따라서 coupling을 낮추게 된다.

정의 Definition

Mediator 패턴의 정수(essence)는 다음과 같다.

어떤 집합의 객체들이 어떻게 상호작용하는 가에 대해 캡슐화하는 객체를 정의하라. Mediator는 객체들이 서로 참조하지 못하도록 함으로써 낮은 커플링을 촉진시키고, 그 클래스들이 독립적으로 상호작용할 수 있도록 해준다.

참가자 Participants

Mediator - Colleague 객체들과 의사소통하기 위한 인터페이스를 정의한다.

ConcreteMediator - Mediator 인터페이스를 구현하고 Colleague 객체간의 의사소통을 조정한다. 이 클래스는 서로 의사소통하기 위해서 모든 Colleague와 그것의 목적을 다 알고 있다.

ConcreteColleague - Mediator를 통해서 다른 Colleague들과 의사소통한다.

예 Example

아래의 예에서 mediator 객체는 3개의 협력하는 버튼들의 상태를 조절한다.: 이렇게 상태를 조절하기 위해 mediator는 book(), view(), search() 메서더를 가진다. 이 3개의 메서드들은 각 버튼의 excute()메서드에 의해 호출된다. 

이로인해, 여기에서 협동 패턴은 각 참여자(버튼)가 mediator를 통해서 그들의 활동에 대해 의사소통하고, mediator는 다른 참가자에게 기대되는 행위를 전달한다.

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
 
//Colleague interface
interface Command {
    void execute();
}
 
//Abstract Mediator
interface IMediator {
    void book();
    void view();
    void search();
    void registerView(BtnView v);
    void registerSearch(BtnSearch s);
    void registerBook(BtnBook b);
    void registerDisplay(LblDisplay d);
}
 
//Concrete mediator
class Mediator implements IMediator {
 
    BtnView btnView;
    BtnSearch btnSearch;
    BtnBook btnBook;
    LblDisplay show;
 
    //....
    void registerView(BtnView v) {
        btnView = v;
    }
 
    void registerSearch(BtnSearch s) {
        btnSearch = s;
    }
 
    void registerBook(BtnBook b) {
        btnBook = b;
    }
 
    void registerDisplay(LblDisplay d) {
        show = d;
    }
 
    void book() {
        btnBook.setEnabled(false);
        btnView.setEnabled(true);
        btnSearch.setEnabled(true);
        show.setText("booking...");
    }
 
    void view() {
        btnView.setEnabled(false);
        btnSearch.setEnabled(true);
        btnBook.setEnabled(true);
        show.setText("viewing...");
    }
 
    void search() {
        btnSearch.setEnabled(false);
        btnView.setEnabled(true);
        btnBook.setEnabled(true);
        show.setText("searching...");
    }
 
}
 
//A concrete colleague
class BtnView extends JButton implements Command {
 
    IMediator med;
 
    BtnView(ActionListener al, IMediator m) {
        super("View");
        addActionListener(al);
        med = m;
        med.registerView(this);
    }
 
    public void execute() {
        med.view();
    }
 
}
 
//A concrete colleague
class BtnSearch extends JButton implements Command {
 
    IMediator med;
 
    BtnSearch(ActionListener al, IMediator m) {
        super("Search");
        addActionListener(al);
        med = m;
        med.registerSearch(this);
    }
 
    public void execute() {
        med.search();
    }
 
}
 
//A concrete colleague
class BtnBook extends JButton implements Command {
 
    IMediator med;
 
    BtnBook(ActionListener al, IMediator m) {
        super("Book");
        addActionListener(al);
        med = m;
        med.registerBook(this);
    }
 
    public void execute() {
        med.book();
    }
 
}
 
class LblDisplay extends JLabel {
 
    IMediator med;
 
    LblDisplay(IMediator m) {
        super("Just start...");
        med = m;
        med.registerDisplay(this);
        setFont(new Font("Arial", Font.BOLD, 24));
    }
 
}
 
class MediatorDemo extends JFrame implements ActionListener {
 
    IMediator med = new Mediator();
 
    MediatorDemo() {
        JPanel p = new JPanel();
        p.add(new BtnView(this, med));
        p.add(new BtnBook(this, med));
        p.add(new BtnSearch(this, med));
        getContentPane().add(new LblDisplay(med), "North");
        getContentPane().add(p, "South");
        setSize(400, 200);
        setVisible(true);
    }
 
    public void actionPerformed(ActionEvent ae) {
        Command comd = (Command) ae.getSource();
        comd.execute();
    }
 
    public static void main(String[] args) {
        new MediatorDemo();
    }
 
}




저작자 표시 비영리 변경 금지
신고

'Design Patterns > 영문 위키(Wikipedia)' 카테고리의 다른 글

Observer pattern  (0) 2012.06.27
Memento pattern  (0) 2012.06.20
Mediator pattern  (0) 2012.06.19
Iterator pattern  (0) 2012.06.18
Interpreter pattern  (0) 2012.06.15
Command Pattern  (0) 2012.06.15
Posted by Code-Moon

댓글을 달아 주세요

먼저 이 글은 영문 위키의 글을 번역한 글임을 알려드립니다.

영어 실력이 부족한 관계로 오역이 있을 수도 있습니다.

원문 주소 :  http://en.wikipedia.org/wiki/Iterator_pattern



Behavioral - Iterator pattern



객체지향 프로그래밍(object-oriented programming)에서, 이터레이터 패턴(iterator pattern)반복자(iterator)컨테이너(container)(List, Set, Map등을 말합니다.)를 돌면서 컨테이너의 요소(elements)에 접근하는 디자인 패턴(design pattern)이다. ; 어떤 경우에 컨테이너에 특화된 알고리즘이 필요한 경우가 있고 따라서 이런 부분은 컨테이너와의 독립성을 유지하기 힘들다.


예를 들어, SearchForElement라는 가상의(hypothetical) 알고리즘이 컨테이너에 특화된 알고리즘으로 구현하지 않고, 특정 타입의 반복자(iterator)를 사용해서 구현할 수 있다. 이렇게 하면 SearchForElement는 그 타입의 iterator(앞에서 구현한 특정타입의 반복자)를 지원하는 어떤 컨테이너에서든지 사용할 수 있게 된다. 

정의 Definition

Iterator Factory method pattern의 본질(essence)은 "세부적인 구현(underlying representation)을 노출시키지 않고서, 컨테이너(aggregate object)의 요소에 차례대로 접근할 수 있는 방법을 제공하는 것"이다.

언어에 특화된 구현 Language-specific implementation

메인 글 : Iterator
일부 언어는 문법을 표준화하고 있다. C++과 Phython이 이에 속한다.

C++

C++ 에서는 구분자(iterator)를 pointer의 의미(semantics)로 구현한다. C++에서 어떤 클래스는 포인터의 모든 오퍼레이션을 오버로드할 수 있어서,  반복자에서 역참조(dereference), 증가, 감소 연산을 완벽히 구현할 수 있다. 이는 평범한 메모리 버퍼에 std::sort같은 알고리즘을 바로 사용할 수 있고, 새로 배워야할 문법이 없다는 장점이 있다. 하지만, 컨테이너의 마지막인지 확인하기 위해서는 반복자가 스스로 알지 못하기 때문에 마지막("end") 반복자를 알고 있어야 한다는 단점이 있다. 우리는 C++에서 반복자가 iterator 컨셉(concept)을 본보기로 하고 있다고 말한다.


Python

Python은 언어자체에서 반복자를 하나의 문법으로 지정하고 있어서 for 같은 키워드와 함께 사용된다. sequence에는 __iter__()라는 메서드가 있는데 이 메서드는 반복자 객체를 반환한다. next()메서드를 통해 다음 요소를 반환하거나, sequence의 끝에 도달하면 StopIteration 예외(exception)를 발생시킨다. 반복자도 __iter__()메서드를 가지고 있어서 스스로를 반환시킬 수 있다.


Java

자바는 Collections 클래스가 구현해야만하는 Iterator 인터페이스가 있다. (그래서 자바의 컬렉션들은 모두 Iterator인터페이스를 구현하고 있고, Map이든 Set이든 List든 상관없이 Iterator 인터페이스를 이용해서 모든 요소 검사를 할 수 있죠.)

저작자 표시 비영리 변경 금지
신고

'Design Patterns > 영문 위키(Wikipedia)' 카테고리의 다른 글

Memento pattern  (0) 2012.06.20
Mediator pattern  (0) 2012.06.19
Iterator pattern  (0) 2012.06.18
Interpreter pattern  (0) 2012.06.15
Command Pattern  (0) 2012.06.15
Chain-of-responsibility pattern  (0) 2012.06.08
Posted by Code-Moon

댓글을 달아 주세요

먼저 이 글은 영문 위키의 글을 번역한 글임을 알려드립니다.

영어 실력이 부족한 관계로 오역이 있을 수도 있습니다.

원문 주소 : http://en.wikipedia.org/wiki/Interpreter_pattern



Behavioral pattern - Interpreter pattern

컴퓨터 프로그래밍(computer programming)에서 interpreter pattern은 어떤 언어에서 어떻게 문장들을 평가할지를 결정하는 디자인 패턴(design pattern)이다. 기본 개념은 특화면 컴퓨터 언어(specialized computer language)에서 각 심볼(terminal 또는 nonterminal)에 대한 클래스(class)를 가지는 것이다. 언어의 어떤 문장에 대한 문맥 트리(syntax tree)는 composite 패턴의 인스턴스이며, 그 문장을 평가(해석)하기 위해 사용된다. 


인터프리터 패턴의 사용 Uses for the Interpreter pattern

  • SQL같은 특화된(specialized) 데이터베이스 쿼리 언어들
  • 주로 통신 프로토콜(communication protocols)을 설명하기 위해 사용되는 특화된 컴퓨터 언어들
  • 대부분의 다목적(general-purpose) 컴퓨터 언어들은 실제로 몇몇 특화된 언어들을 포함한다.


구조 Structure



예 Example

아래의 Reverse Polish notation 예는 interpreter 패턴을 묘사하고 있다.

expression ::= plus | minus | variable | number
plus ::= expression expression '+'
minus ::= expression expression '-'
variable  ::= 'a' | 'b' | 'c' | ... | 'z'
digit = '0' | '1' | ... '9'
number ::= digit | digit number

위의 문법은 아래의 reverse Polish 표현법을 포함하는 언어를 정의한다.


a b +
a b c + -
a b + c a - -



아래의 interpreter 패턴은 각 문법 법칙에 대한 클래스이다.




interpreter 패턴은 parsing에 대해 언급하지 않지만 완벽함을 위해서 파서(parser)를 제공한다.



마지막으로 w = 5, x = 10, z = 42 일 때 "w x z - +"라는 표현식을 평가한다.


저작자 표시 비영리 변경 금지
신고

'Design Patterns > 영문 위키(Wikipedia)' 카테고리의 다른 글

Mediator pattern  (0) 2012.06.19
Iterator pattern  (0) 2012.06.18
Interpreter pattern  (0) 2012.06.15
Command Pattern  (0) 2012.06.15
Chain-of-responsibility pattern  (0) 2012.06.08
Proxy pattern (프록시 패턴)  (0) 2012.06.06
Posted by Code-Moon

댓글을 달아 주세요

티스토리 툴바