전체 글 311

상태 패턴(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;..

책임 사슬(Chain of Responsibility Pattern)

포인터 사슬 크리처가 이름, 공격력, 방어력을 가지고 있습니다. 게임 플레이 도중 공격력과 방어력이 어떤한 이벤트에 의해 변경이 됩니다. 이를 위해 CreatureModifier를 호출합니다. 이벤트들이 여러번 발생하여 CreatureModifier가 여러번 호출 될 수 있도록 변경 작업을 크리처 별로 쌓아 순서대로 변경 될 수 있도록 합니다. 즉, 연결된 고리의 어느 한 객체가 실제 상황에 적합하다고 판단되면 자신에게 정의된 서비스를 제공합니다. 게임에 크리처들이 있고 이름, 공격력, 방어력 속성을 가지고 있습니다. struct Creature { string name; int attack, defense; Creature(const string& name, const int attack, const ..

모던 C++ 디자인 패턴

'디자인 패턴'을 생각하면 가장 먼저 떠오르는 것이 'GoF design patterns'을 것입니다. GoF의 디자인 패턴 책을 읽어 보신 분들은 아시겠지만 설명이 난해하고 책에서 들어 놓은 예는 그렇게 공감을 주고 있지도 않습니다. 그렇지만, 이 책은 1994년에 출간되어 현재까지도 프로그래머들에게 필독서로서 객체 지향 설계에 있어서 바이블과 같은 책입니다. '모던 C++디자인 패턴'은 현대에는 프로그래밍의 쓰임과 C++ 언어의 진화에 따른 패러다임이 변화하였으며 이에 맞추어 'Gof의 디자인 패턴'을 재해석 하여 여러분들이 알기 쉽도록 풍부한 예외 실용적인 내용들로 디자인 패턴들을 소개하고 있습니다. 'Gof의 디자인 패턴'을 읽어 보지 못했다면 꼭 이책을 먼저 읽어 보시길 권합니다. 이후 'Hea..

독서 리뷰 2020.03.04

프락시 패턴(Proxy Pattern)

프록시 패턴도 데커레이터 패턴처럼 어떤 객체의 기능을 수정/확장한다는 목적이 비슷합니다. 기존 API의 사용 방식을 정확히 동일하게 유지하면서 그 내부 동작만 다르게 한다는 점에서 다릅니다. 같은 API에 대해서 서로 다른 종류의 서로 다른 목적의 완전히 다른 프로시들이 여러 개발자에 의해서 만들어질 수 있습니다. 스마트 포인터 가장 단순하면서도 직접적인 프록시 패턴의 예는 스마트 포인터입니다. 스마트 포인터는 일반적인 포인트를 사용할 때와 완전히 동일한 방식으로 사용할 수 있습니다. 즉, 보통의 포인터가 가진 인터페이스를 유지합니다. 일반 포인터의 인터페이스를 그대로 유지하면서 다른 목적의 기능이 구현되었습니다. 속성 프록시 C++에서 어떤 필드에 필별히 지정된 접근자/변경자를 부여하고 싶다면 속성 프..

반응형