반응형

프로그래밍 일반/디자인 패턴 22

방문자 패턴(Visitor Pattern)

방문자 패턴은 어떤 객체의 계층 각각마다 서로 다른 작업을 수행해야 할때 사용하면 좋습니다. 기존 코드의 수정 없이 새로운 방문자를 추가하는 것만으로도 기능을 확장 할 수 있습니다. 기능 확장면에서 OCP 충실히 따를 수 있습니다. 다음과 같이 DoubleExpression과 AdditionExpression 수식이 있고 각 수식마다 새로운 동작을 추가해야 할때를 생각해봅시다. struct Expression { }; struct DoubleExpression : Expression { double value; explicit DoubleExpression(const double value) : value{value} {} }; struct AdditionExpression : Expression { E..

템플릿 메서드 패턴(Template method Pattern)

전략 패턴과 템플릿 메서드 패턴은 매우 유사합니다. 전략 패턴이 구성을 이용하지만 템플릿 메서드 패턴은 상속을 이용합니다. 핵심 원리는 알고리즘과 상세 구현을 분리하여 구현하는 것입니다. 게임 시뮬레이션 보드 게임류는 게임 시작, 턴 플레이, 승자 결정이 되고 게임 종료됩니다. class Game { public: explicit Game(int number_of_players) : number_of_players(number_of_players) {} // 게임의 알고리즘 void run() { start(); while (!have_winner()) take_turn(); cout

전략 패턴(Strategy Pattern)

구성(Composition)을 이용하여 알고리즘과 상세 구현을 분리하여 구현하는 것입니다. 런타임에 변경 가능한 동적형태와 템플릿으로 컴파일 타임에 결정되는 정적 형태가 있습니다. 전략 패턴은 알고리즘의 골격만을 정의하고 세부 구현은 구성(Composition)으로서 특정 전략을 선택적으로 채워 넣을 수 있게 하는 것입니다. 앞으로 단순한 텍스트 목록을 두 가지 포맷(HtmlList, MarkdownList)으로 전략적으로 선별하여 렌더링 하는 것을 구현합니다. 동적 전략 구성(Composition)을 이용하며 런타임에 전략을 동적으로 결정합니다. 전략 패턴의 골격을 위한 ListStrategy 클래스를 구현합니다. struct ListStrategy { virtual void add_list_item(..

상태 패턴(State Pattern)

"상태가 동작을 제어하고, 상태는 바뀔 수 있다."는 매우 단순한 아이디어 입니다. 졸음(상태) – 커피(트리거) → 정신이 듦(상태) 상태 패턴의 구현에는 기본적으로 다음의 두 가지 방법이 있습니다. 동작을 가지는 실제 클래스로 상태를 정의합니다. 그리고 그 동작들은 상태가 이전될 때 클래스의 변화에 따라 변경됩니다. 상태와 상태 전이를 단순히 enum 타입처럼 식별자의 나열로 정의합니다. 실제 상태 변화는 상태 머신 이라는 특별한 컴포넌트를 두어 수행합니다. 상태 기반 상태 전이 가장 간단한 예로 전등을 생각해봅시다. 꺼짐과 켜짐 상태가 있으며 어떤 상태로든 전이 할 수 있습니다. 상태를 enum이 아니라 클래스로 정의합니다. LightSwitch는 State와 상태를 전이할 수 있는 수단을 가지며 ..

관찰자 패턴(Observer Pattern)

SNS에서 Follow하여 구독하거나 구독 취소를 하는 것이 옵저버 패턴과 동일한 행위입니다. 옵저버 패턴은 실제 세상에서도 그 예가 많 듯이 어플리케이션 구현시에도 자주 필요하며 즐겨 사용되는 디자인 패턴입니다. Person 클래스의 변경 사항을 모니터링하는 Person Observer의 구현을 살펴 보겠습니다. age에 쓰기 작업이 있을때마다 콘솔 메시지를 출력하는 구현입니다. 이 구현은 전형적인 옵저버 패턴의 형태입니다. (책에서 과제로 남겼던, std::any를 이용하여 제너릭으로 구현하였습니다) templatestruct Observer { virtual void field_changed(T& source, const string& property_name, const any new_value)..

Null 객체

인터페이스를 마음대로 선택하여 사용할 수 없는 경우가 있습니다. 예를들어 어떤 모듈의 특정 기능을 사용할 경우 원하지 이 모듈이 인터페이스에 내장되어 있을 수 있습니다. 이럴때 Null 객체를 이용합니다. 시나리오 다음과 같은 인터페이스를 가진 Logger 라이브러리를 사용한다고 가정합니다. struct Logger { virtual void info(const string& s) = 0; }; Logger를 상속받은 ConsoleLogger를 구현합니다. struct ConsoleLogger : Logger { void info(const string& s) override { cout

메멘토 패턴(Memento Pattern)

커맨드 패턴에서, 시스템의 모든 변경 이력을 기록해 과거의 어떤 지점으로든 상태를 되돌릴 수 있는 내용을 살펴 보았습니다. 모든 임의의 과거가 아니라 필요한 때 특정 시점으로 되돌릴 수만 있으면 충분한 경우가 있습니다. 메멘토 패턴은 바로 이런 경우 이며 특정 시점의 시스템 상태를 전용 객체에 저장하여 리턴합니다. 이렇게 저장된 객체를 이용하여 저장되어 있던 상태로 되돌릴 수 있습니다. 은행 계좌 다음은 BankAccount 클래스의 정의입니다. class BankAccount { int balance = 0; public: explicit BankAccount(const int balance) : balance(balance) { } Memento deposit(int amount) // 예금 처리후 ..

커맨드 패턴(Command Pattern)

커맨드 패턴은 어떤 객체를 활용할 때 직접 그 객체의 API를 호출하여 조작하는 대신, 작업을 어떻게 하라고 명령을 보내는 방식입니다. 데이트를 조작할때 그 데이터를 직접 조작하면 어떠한 변경 이력도 남지 않습니다. 때문에 데이터를 관리/감시 하거나 이력 기반으로 디버깅을 하거나 데이터를 되돌릴 필요가 있을 경우 커맨드 패턴이 유용하게 사용 될 수 있습니다. 객체로 명령을 만듭니다. 이를통해 명령을 대기, 로깅, 되돌릴 수 있는 기능을 지원 할 수 있습니다. 시나리오 입금, 출금 기능을 가진 은행의 마이너스 통장이 있습니다. 금융 감사를 위해 모든 입출금 내역을 기록해야 합니다. 그런데 이 입출금 기능은 이미 만들어졌으며 동작중이므로 수정할 수 없는 상황입니다. struct BankAccount { in..

중재자 패턴(Mediator Pattern)

중재자는 컴포넌트 간의 커뮤니케이션을 돕기 위한 메커니즘입니다. 컴포넌트들이 서로 직접 참조하지 않고 매개자가 모든 컴포넌트들을 참조합니다. 각 컴포넌트들은 서로를 참조하지 않아도 되므로 느슨한 결합이됩니다. 채팅룸 채팅룸은 매개자 디자인 패턴의 가장 전형적인 예입니다. Person은 메시지 수신하고, 채팅 그룹에 말을 하고, 개인 메시지 보내기를 요청 합니다. struct Person { string name; ChatRoom* room = nullptr; vector chat_log; Person(const string& name); void receive(const string& origin, const string& message); void say(const string& message) con..

반복자 패턴(Iterator Pattern)

내부를 노출하지 않고 어떤 컬렉션에 속한 항목들을 순차적으로 접근할 수 있는 방법을 제공합니다. 컬렉션의 항목 하나에 접근하는 방법과 그 항목의 다음 항목으로 이동하는 방법을 알고 있는 것을 반복자라 합니다. 표준 라이브러리의 반복자 stl의 vector, map, list 등의 iterator는 이미 우리에게 익숙하며 잘 알것이라고 생각합니다. 이진 트리의 탐색 전통적인 컴퓨터 과정에서 다루는 이진 트리 탐색을 살펴봅시다. Node는 left, right, parent 그리고 전체 tree에 대한 참조를 가집니다. template struct Node { T value = T(); Node* left = nullptr; Node* right = nullptr; Node* parent = nullptr;..

반응형