Design Pattern for Smalltalk – State

t_Dpsc_chapter05_State_01

디자인 패턴은 몇가지로 분류된다. 생성,구조,행위 의 3가지가 그것인데 특히 행위(behaviord) 패턴에 속하는 패턴들은 객체들 사이의 관계를 통해 어떤 결과가 일어나는지에 초점이 맞춰져 있다. State 패턴도 그 중 하나이다. State 패턴은 이름 그대로 “상태”를 객체로 표현하는 것이 목적이다. 하지만 중요한 것은 “왜 상태를 상수가 아닌 굳이 객체로 정의하는가”에 대한 것과 “이렇게 정의 된 상태는 어떻게 사용되는가”정도가 될 것이다.

State 패턴의 내용을 간략하게 정리해보자.

1. Client 는 context와 작업한다.
2.context 내부에서는 언제나 동일한 개념으로 State 인스턴스를 다룬다. (ex: state :: Open ( ) 호출 등)
3. context 내부에서 관리되는 State의 인스턴스가 상황에 맞게 교체되기 때문에 open 메서드의 동작결과는 바뀌게 된다.

이런 State의 동작원칙 덕분에 context 객체의 내부에서는 메세지를 다루는 작업에 대한 일관성을 확보하게 된다.

State 클래스의 추상클래스화를 통한 State의 다양한 상태를 수평적으로 늘일 수 있다. State가 표현해야 하는 각 상태를 상수로 정의하면 context 객체 내부에는 상수값을 판별해서 동작하는 내부조직이 직접 구현되어 있어야만 한다.

하지만 State 객체를 쓰면 상태에 따른 동작을 State 클래스군에서 책임지기 때문에 상태별 동작에 따른 코드를 새로운 Context 마다 복사해서 사용하는 대신에, 재사용을 쉽게하며 상태별 동작에 대한 코드의 유지보수를 보다 쉽게 할 수 있다. State의 하위 인스턴스는 그 자체로 상태의 타입을 의미하기 때문에 State의 인스턴스에게 동적인 리소스를 가지고 있게 구조를 만드는 것은 피하도록 하다. Context인스턴스 내부에서 관리되는 State 변수의 인스턴스 교환/관리는 context의 몫이지만 State 클래스군에 상태별 규칙을 넣어 State의 하위 클래스들간에 서로 상호작용하며 반응하게 할 수 있다면 보다 좋은 구현이 될 것이다.

Design Pattern for Smalltalk – Observer

t_Dpsc_chapter05_Observer_01

모든것이 객체(클래스)로 이루어져있는 Smalltalk 같은 시스템이나 객체지향 언어로 만들어진 어플리케이션은, 그 내부에 수많은 객체를 가지고 있게 된다. 당연히 물리적으로 보자면 바이너리(이진) 데이터의 나열에 지나지 않기 때문에 비-객체지향 언어로 만들어진 어플리케이션과 본질적인 차이는 없지만, 여기서는 논리적인 구조를 다루고 있으니 그 점은 넘어가도록 하자. 여튼 이렇게 수많은 객체사이에 특정 객체를 바라보는 객체를 B라고 하고 특정 객체를 A라고 가정하자. A의 내부에서 변수의 내용이 갱신되었을 때 이 내용을 B에게 알려줘야 하는 경우가 되었다면 어떻게 해야할까? 그리고 이 B가 한개가 아니라 복수로 존재한다면 A는 어떻게 해야할까? observer패턴은 이런 경우를 풀어내기 위해 고안된 방법이다.

객체지향은 사람의 생각을 기본 모델로 해서, 생각에서 이루어지는 관계를 체계적이고 효율적으로 정리해서 구현 및 적용한 방법이다. 그렇기 때문에 이 패턴 역시 사람과의 관계에 비추어서 생각 해 보면 조금 이해하기 쉬울것이다. 나는 무언가를 가지고 관리하는 사람이고, 이런 나와 관련된 업무를 하는 다른사람이 여럿 있다고 가정하자. 이 때 다른 사람들은 내 무언가의 상태가 변화될 때 영향을 받는 업무라고 할 때 어떻게 해야 효율적일까.

당연히 나는 무언가의 상태를 관리하며 다른 사람에게 상태의 변화를 통지해주는게 가장 효율적인 방법이 될 것이다. 이 때의 나를 subject라고 하고 다른 사람을 observer라고 이해하면 된다.

observer패턴의 진행을 간단하게 보면 다음과 같다.

1. data 객체가 자신을 창조하는 객체들에게 notification을 보내서 자신의 상태변경을 알린다.
2. notification을 받은 객체는 data 객체내에서 갱신된 자료를 가져온다.

이 때 data객체가 자신을 참조하는 객체의 목록을 관리한다는 점에서는 proxy 패턴의 reference counter와 통하는 부분도 있다.

t_unnamed0

data객체를 참조하는 참조객체의 수가 1 이상일 때 data 객체에 최초의 데이터 요청이 오면 data객체 내에서 데이터를 캐싱해서 관리하고, 참조객체의 수가 0이면 data와 DB의 연결을 끊어서 리소스의 낭비를 줄일 수도 있다.

Design Pattern for Smalltalk – Memento

t_Dpsc_chapter05_Memento_01

Memento패턴은 기록에 대한 패턴이다. 기록이 필요한 이유는 무엇일까? 기록을 참고해야할 무언가가 있기 때문이다. 기록이 존재함으로서 과거의 이력을 살펴보고, 그 결과로 무언가 다른 행동을 할 수도 있다. 이 경우 다른 행동은 redo/undo 가 될 것이다.

여기서 잠시 객체지향의 3대 요소를 생각해보자. 그렇다! 상속성, 캡슐화, 다형성이다. Memento 패턴이 존재하는 이유를 생각해보자. 객체의 기본은 자신의 내부상태를 외부에 드러내지 않고 동작하는 것에 있다. redo/undo 를 위해 자신의 상태를 필요할 때 마다 외부에서 접근 가능하게 드러내는 것은 캡슐화의 원칙에 위배된다. 이런 필요 덕분에 Memento패턴이 구상되었다. 객체가 필요할 때 자신의 상태를 저장하는 “자신 전용의 별도 창고”에 보관하고, 외부에서의 요청이 있을 때 스스로가 창고에 접근해서 필요한 정보를 용도에 맞게 사용하면 된다.

originator의 Memento class 는 내부적으로 command 패턴 (status의 히스토리 목록을 유지)을 구현하고, 어플리케이션 전첵적으로 command 패턴을 사용하여 이 전체적 패턴에 Originator에 대한 히스토리를 남겨서 관리하면 서로의 간섭이 적은 redo/undo를 구현 할 수 있다. originator의 memento인스턴스 내부에서는 데이터를 collection으로 관리한다고 했을 때, originator의 클라이언트는 memento의 인스턴스를 인식할 수 없기 때문에 캡슐화가 위배되는 경우를 비껴가는데도 유용하다.