'행위적 패턴'에 해당되는 글 5건

  1. 2012.07.05 Template method pattern
  2. 2012.06.20 Memento pattern
  3. 2012.06.18 Iterator pattern
  4. 2012.06.15 Interpreter pattern
  5. 2012.06.15 Command Pattern

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

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

원문주소 : 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/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/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

댓글을 달아 주세요

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

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

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



Behavioral pattern - Command Pattern



객체 지향 프로그래밍(object-oriented programming)에서 command pattern(이하 커맨드 패턴)은 나중에 호출할 메서드를 위한 모든 정보를 대표(represent)하고 캡슐화(encapsulate)하는 디자인 패턴(design pattern)이다.

이 정보에는 메서드 이름, 메서드를 소유하고 있는 객체 그리고 메서드 인자에 필요한 값들을 포함하고 있다.


커맨드 패턴과 항상 연관되는 세가지 조건은 클라이언트(client), 호출자(invoker), 수신자(receiver)이다. 클라이언트(client)는 커맨드 객체를 인스턴스화하고, 나중에 메서드를 호출하는데 필요한 정보들을 제공한다. 호출자(invoker)는 메서드가 언제 호출되어야하는지 결정한다. 수신자(receiver)는 메서드 코드를 포함하고 있는 클래스의 객체이다.


커맨드 객체를 사용하는 것은 한 메서드를 어떤 클래스가 가지고 있든지 메서드의 인자가 무엇인지 알 필요없이 그 메서드를 원하는 시점에 위임하거나 호출할 필요가 있는 일반적인 컴포넌트를 만들기 쉽게 해준다.

사용 Uses

커맨드 객체는 다음과 같이 구현하기에 용이하다.


다단계 취소 Multi-level undo

만약 어떤 프로그램의 모든 사용자 액션이 커맨드 객체로 구현되어 있다면, 그 프로그램은 가장 최근에 실행한 명령들에 대한 스택(stack)을 유지할 수 있다. 사용자가 어떤 명령을 취소하고 싶다면, 그 프로그램은 그냥 가장 최근의 명령을 스택에서 뽑아내고(pop) undo()메서드를 호출하면 된다.


Transactional behavior

undo와 비슷하게, 데이터베이스 엔진이나 소프트웨어 설치 프로그램은 이미 수행한 오퍼레이션의 리스트나 앞으로 수행할 오퍼레이션의 리스트를 유지할 필요가 있을지도 모른다. 만약 그 오퍼레이션 중 하나라도 실패하게 된다면 나머지 모든 오퍼레이션도 취소될 수 있다.(일반적으로 rollback이라 부른다.) 예를들면, 두개의 데이터베이스 테이블이 있고 이 둘 중 하나가 수정되면 나머지 하나도 업데이트해야하는 관계일 때, 두번째 테이블의 업데이트가 실패하면 트랜젝션이 롤백(rolled back)되고, 첫번째 테이블은 무효한 레퍼런스를 가지고 있지 않는다.


Progress bars

어떤 프로그램이 일련의 명령들을 가지고 있고, 이 명령이 차례대로 수행된다고 가정해보자. 만약 각 명령 객체가 getEstimatedDuration()메서드를 가지고 있다면, 그 프로그램은 전체 수행 시간을 쉽게 추정할 수 있을 것이다. 이를 이용해서 프로그램이 모든 태스크 중 얼마나 완료했는지를 보여줄 수 있는 프로그래스 바에 적용할 수 있다.


Wizards

종종 wizard는 사용자가 마지막 페이지에 있는 "완료"버튼을 누르면 하나의 액션이 수행되는 여러 페이지의 설정을 나타낸다. 이러한 경우에 애플리케이션의 코드로부터 사용자 인터페이스 코드를 분리하는 자연스러운 방법은 커맨드 객체를 이용해서 wizard를 구현하는 것이다. 커맨드 객체는 wizard가 처음 화면에 나타낼 때 만들어진다. 각 wizard 페이지는 GUI의 변화를 커맨드 객체에 저장해서, 이 깨체가 사용자 진행상태로 이주된다.(populate, 원래는 거주하다라는 뜻인데,, 여기에서는 이 커맨드 객체가 사용자의 진행상태를 가지고 있게 된다 정도로 이해하면 될 것 같습니다.) "완료"는 단순히 execute()를 호출하도록 한다. 이 방법으로 커맨드 클래스는 일체의 사용자 인터페이스 코드를 가지지 않게 된다.


GUI 버튼과 메뉴 항목 GUI buttons and menu items

스윙(Swing)Borland Delphi 프로그래밍에서 Action은 커맨드 객체이다. 요구되어지는 명령을 수행하는 것 외에도 Action은 관련된 아이콘, 키보드 단축키, 툴팁 글자 등을 가질 수도 있다. 툴바 버튼이나 메뉴 항목 컴포넌트는 Action 객체를 이용해서 완벽하게 초기화될 수도 있다.


쓰레드 풀 Thread Pools

전형적으로, 일반적인 목적의 쓰레드 풀 클래스는 public 메서드인 addTask()를 가지고 있을지도 모른다. 이 메서드는 내부 큐(queue)에 작업 아이템을 추가하는 메서드이다. 이는 큐에 있는 명령을 수행하는 쓰레드의 풀을 유지한다. 큐에 있는 아이템은 커맨드 객체이다. 전형적으로 이런 객체들은 java.lang.Runnable같은 공통 인터페이스를 구현하는데, 이는 쓰레드 풀이 어떤 태스크를 수행할지에 대해 전혀 알지 못해도 된다.


Macro recording

만약 모든 사용자 액션이 커맨드 객체에 의해 표현된다면, 프로그램은 커맨드 객체가 수행되는대로 그 리스트를 유지함으로써 간단하게 일련의 액션들을 저장할 수 있다. 그리고나서 같은 커맨드 객체들을 차례대로 수행함으로써 같은 액션을 "다시 재생(play back)"할 수 있다. 만약 프로그램이 스크립팅 엔진을 사용하고 있다면, 각 커맨드 객체는 toScript()메서드를 구현할 수 있고, 사용자 액션은 스크립트로써 간단히 저장될 수 있다.


네트워킹 Networking

전체 커맨드 객체를 네트워크를 통해서 다른 머신에서 수행되도록 하는 것이 가능하다. 예를들면 컴퓨터 게임에서 플레이어의 액션을 볼 수 있다.


병렬 처리 Parallel Processing

명령이 공유 자원에 태스크로 쓰여지고, 많은 쓰레드에 의해 병렬적으로 수행되는 경우( 원격 머신의 경우 - 이 변형은 종종 Master/Worker 패턴으로 언급된다.)


Mobile Code

URLClassLoader와 Codebase를 통해서 한 곳에서 다른 한 곳으로 코드를 스트리밍할 수 있는 Java같은 언어를 사용함으로써, 명령이 원격지에 전송되도록 할 수 있다.(EJB Command, Master Worker)

구조 Structure


  • 위의 Receiver에 대한 설명은 "커맨드에 의해 수행되는 실질적인 작업"이라 할 수 있다.

전문 용어 Terminology

커맨드 패턴 구현을 설명하기 위한 용어는 일관적이지 않아서 혼란스러울 수도 있다. 이는 모호함(ambituity), 유의어(synonyms)의 사용, 원래 패턴에 대한 불분명할 수 있는 구현이라는 결과로 나타난다.

  1. 모호함(Ambiguity)
    1. command라는 용어는 모호하다. 예를들어 move up, move up은 2번 수행되는 하나의 (move up) 명령일 수도 있고, 같은 일(move up)을 하는  두 개의 (다른)커맨드를 의미할 수도 있다. 만약 첫번째 경우라고 할때 명령이 undo 스택에 두번 들어가면, 스택에 있는 두 아이템은 같은 커맨드 객체를 가리킨다. 이는 어떤 명령이 항상 같은 방법으로(여기에서는 예를들면 move down) 취소된다고하면 적절할 것이다. Gang of Four와 아래의 자바 예에서는 커맨드라는 용어를 이와 같은 방법으로 이해하고 있다. 반면에 후자의 경우에 undo 스택에 커맨드를 추가하면 두개의 다른 객체가 들어가게 될 것이다. 이는 스택에 있는 각각의 객체들이 명령이 취소되는데 필요한 정보를 가지고 있는 경우에 적절할 것이다. 예를 들어, "선택 영역 삭제"라는 명령을 취소하기 위해서 그 객체는 삭제된 텍스트의 사본을 가지고 있을 수도 있다. 그래서 "선택 영역 삭제"가 취소되어야 할 때 그 텍스트가 다시 추가될 수 있는 것이다. 어떤 명령의 각 호출에 대해 다른 객체를 사용하는 것은 chain of responsibility pattern의 한 예임을 알아두어라.
    2. execute라는 용어 또한 모호하다. 이는 command 객체의 excute 메서드에 의해 특정 코드를 수행하는 것을 의미할 수도 있다. 하지만, 마이크로소프트의 WPF(Windows Presentation Foundation) 에서 커맨드는 excute메서드가 호출됐을 때 커맨드가 수행됐음을 의미하지만, 이것이 애플리케이션 코드가 수행되었음을 필연적으로 의미하는 것은 아니다. 그는 약간의 이벤트 처리 후에만 발생한다.
  2. 유의어와 동음 이의어(Synonyms and homonyms)
    1. Client, Source, Invoker : 사용자에 의한 버튼, 툴바 버튼, 메뉴 항목 클릭, 단축키가 눌러짐.
    2. Command Object, Routed Command Object, Action Object : command와 관련있는 단축키, 버튼 이미지, 커맨드 텍스트 등에 대해 알고있는 싱글톤 객체. source/invoker 객체는 Command/Action 객체의 excute/performAction 메서드를 호출한다. Command/Action 객체는 command/action의 유용성(availability)이 바뀌었을 때 적절한 source/invoker 객체에게 알려준다. 이는 command/action이 excute/perform할 수 없을 때 버튼과 메뉴 항목을 비활성화(회색으로)시킬 수 있도록 한다.
    3. Receiver, Target Object : 복사, 붙여넣기, 또는 움질일 객체. receiver 객체는 command의 excute 메서드에 의해 호출되는 메서드를 가지고 있다. receiver는 전형적으로 target 객체이기도 하다. 예를들어, receiver 객체가 cursor이고, 이 객체의 메서드가 moveUp이라면, cursor는 moveUp 액션의 target이라고 생각될 수 있을 것이다. 반면에, 만약 코드가 command 객체 자신에 의해 정의되어진다면 target 객체는 완전히 다른 객체일 것이다. 
    4. Command 객체, routed event 인자들, event 객체 : 소스(source)로부터 Command/Action 객체로, Target 객체로, 그것이 동작하는 코드로 전달되는 객체. 각 버튼 클릭이나 단축키는 새로운 command / event객체에 새로운 결과를 야기한다. 일부 구현에서는 CopyCommand같은 객체로부터 문서 영역(document section)같은 객체로 전달되기 때문에 command/event 객체에 더 많은 정보를 추가한다. 다른 구현에서는 네이밍 충돌(naming conflicts)를 피하기 위해 데이터를 한줄로 이동시키기때문에 command / event 객체를 다른 event 객체에 넣어둔다.(큰 박스 안에 작은 박스가 있는 것처럼. chain of responsibility pattern을 보라.)
    5. Handler, ExecutedRoutedEventHandler, method, function : 복사, 붙여넣기, 옮기기 등을 실제로하는 코드. 일부 구현에서 handler코드는 command/action 객체의 일부이다. 다른 구현에서는 Receiver/Target객체의 일부이고, 또 다른 구현에서 handler코드는 다른 객체로부터 분리되어진다. 
    6. Command Manager, Undo Manager, Scheduler, Queue, Dispatcher, Invoker : command / event객체를 undo 스택이나 redo스택에 넣는 객체. 또는 다른 객체가 command/event객체에 대해서 어떤 액션을 취할 준비가 될때까지 command / event 객체에 유지하고 있는 객체. 또는 command / event객체를 적절한 receiver/target 객체나 handler 코드에 보내는 객체.
  3. 원래 command 패턴을 뛰어넘는 구현
    1. routed 커맨드를 도입하고 있는 마이크로소프트의 Windows Presentation Foundation (WPF)는 command 패턴과 event 처리를 합쳐놓았다. 그 결과 command 객체는 더 이상 target객체에 대한 레퍼런스 뿐만 아니라 애플리케이션 코드에 대한 레퍼런스도 가지고 있지 않다. 대신에 command 객체의 execute 메서드를 호출하는 것은 소위 말하는 Executed Routed Event가 호출되는 결과를 야기한다. 이 때 Executed Routed Event 는 event의 터널링(tunneling)또는 버블링(bubbling)을 하는 동안 binding과 직면할 수 있는데, binding은 target과 애플리케이션 코드를 확실히 해준다.



예 Example

"간단한" 스위치를 생각해보자. 이 예에서 Switch는 2개의 command를 가지고 있다. (불을 켜는 것과 불을 끄는 것)

이런 command패턴의 구현의 이점은 스위치가 어떤 기기에 상관없이 사용될 수 있다는 것이다. (불(light)뿐만 아니라 다른 것과 관련해서도 사용될 수 있다.) - 이 예에서는 불을 켜고 끄는 스위치이지만, Switch의 생성자에서는 Command의 어떤 서브클래스든지 받을 수 있다. 예를들어, 엔진에 시동을 거는 스위치를 만들 수도 있다. 


아래의 샘플 애플리케이션은 실제 전기 회로의 모델화한 것은 아니라는 점을 확실히하자. 전기적인 스위치는 벙어리다(dumb, 바보 정도로 해석해도 될 것 같네요). 실제 이진 스위치는 붙었는지 떨어졌는지 여부만 알 수 있다. 스위치는 회로에 연결되어 있을 수 있는 어떤 직접적인 부하(loads)와의 관계에 대해 알지도 못하고 가지지도 못한다. 스위치는 단순히 현재 상태에 대한 이벤트만 알릴 뿐이다. (ON 또는  OFF). 그러면 회로는 상태 엔진(State Engine)을 가지고 있어야 하는데, 이 상태엔진은 다양한 시점에서 적절한 많은 부하와 스위치가 있는 복잡한 회로를 수용하기 위해 회로의 상태를 관리한다. 그리고 각 부하는 특정 회로이 상태에 대한 조건이다. 결론을 내리자면 스위치는 어떤 램프의 자세한 내용에 대해서도 알지 못한다. 


Java


Python

class Switch(object):
    """The INVOKER class"""
    def __init__(self, flip_up_cmd, flip_down_cmd):
        self.flip_up = flip_up_cmd
        self.flip_down = flip_down_cmd
 
class Light(object):
    """The RECEIVER class"""
    def turn_on(self):
        print "The light is on"
    def turn_off(self):
        print "The light is off"
 
class LightSwitch(object):
    """The CLIENT class"""
    def __init__(self):
        lamp = Light()
        self._switch = Switch(lamp.turn_on, lamp.turn_off)
 
    def switch(self, cmd):
        cmd = cmd.strip().upper()
        if cmd == "ON":
            self._switch.flip_up()
        elif cmd == "OFF":
            self._switch.flip_down()
        else:
            print 'Argument "ON" or "OFF" is required.'
 
# Execute if this file is run as a script and not imported as a module
if __name__ == "__main__":
    light_switch = LightSwitch()
    print "Switch ON test."
    light_switch.switch("ON")
    print "Switch OFF test."
    light_switch.switch("OFF")
    print "Invalid Command test."
    light_switch.switch("****")


C#


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

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

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
Flyweight pattern (플라이웨이트 패턴)  (0) 2012.06.05
Posted by Code-Moon

댓글을 달아 주세요

티스토리 툴바