Basic Principles used Patterns
(OOD(객체지향개발)의 원칙들)
Open Close Principle (개방 폐쇄 법칙)
확장에 대해선 개방되며 변경에 대해선 폐쇄 되는 방법.
클래스 상속을 일반적인 예로 자주 든다.
연관 패턴: GoF] Template Method, Strategy, Bridge ridge, POSA] Reactor
Dependency Inversion Principle (의존 관계 역전 원칙)
Hollywood Principle이라고도 함.
(지원자는 이력서를 내고 회사에선 일일이 대응할 필요 없이 몇몇 합격자에게만 연락하면된다.)
부모클래스에서 자식 클래스의 메소드를 호출하는 경우처럼 역전(Inversion)이 일어나는 모습.
패턴처럼 객체들이 등록하고 통지해주는 옵저버 패턴과 비슷함.
객체와의 복잡한 커뮤니케이션이 있을때 고려해볼만 함.
Liskov Substitution Principle (리스코프 치환 원칙)
서브클래스는 사용자가 그 차이점을 알 필요없이 기본 클래스의 인터페이스를 통하여 사용이 가능해야 한다.
즉, 기본 클래스에 정의된 모든 루틴들은 파생 클래스에서 사용될 때 같은 것을 의미해야 한다.
다른 방법을 말해보면 기본 클래스는 모든 자식클래스들의 precondition을 지니고 있는 형태가 된다.
실 구현 사례 : ODBC/JDBC
Single Responsibility Pinciple (단일 책임 원칙)
클래스가 변화되는 이유는 한가지여야 한다.
결국 하나의 책임만 갖도록 한다.
Interface Segregation Principle (인터페이스 분리 원칙)
자신과 관계 없는 인터페이스로 인해 변하면 안된다.
즉, 하나의 종합적인 인터페이스 보다는 구체적인 여러개의 인터페이스 구조가 낫다.
참조 강좌 :
GoF Design Patterns
Abstract Factory, Builder, Factory Method, Prototype, Singleton
Behavioral Patterns (행위 패턴)
Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento,
Observer, State, Strategy, Template Method, Visitor
참조 강좌 : wikipedia 디자인 패턴
참조 샘플 : 디자인 패턴별 샘플 코드 사이트
참조 문서 : StarUML에 포함되어있는 패턴 문서 (UML 이미지 출처이기도 함)
Design Patterns Quick Reference
Abstract Factory (Kit) (생성 패턴)
sample]
#include <iostream>
using std::cout;
using std::endl;
//Products
class AbstractProductA
{
public:
AbstractProductA(){}
~AbstractProductA(){}
virtual void operationA() = 0;
};
class AbstractProductB
{
public:
AbstractProductB(){}
virtual ~AbstractProductB(){}
virtual void operationB() = 0;
};
class ProductA1 : public AbstractProductA
{
public:
void operationA() {cout << "ProductA1::operationA()" << endl;}
};
class ProductA2 : public AbstractProductA
{
public:
void operationA() {cout << "ProductA2::operationA()" << endl;}
};
class ProductB1 : public AbstractProductB
{
public:
void operationB() {cout << "ProductB1::operationB()" << endl;}
};
class ProductB2 : public AbstractProductB
{
public:
void operationB() {cout << "ProductB2::operationB()" << endl;}
};
//Abstract Factory
class AbstractFactory
{
public:
virtual AbstractProductA* CreateProduceA() = 0;
virtual AbstractProductB* CreateProduceB() = 0;
};
class ConcreteFactory1 : public AbstractFactory
{
public:
AbstractProductA* CreateProduceA() {return new ProductA1();}
AbstractProductB* CreateProduceB() {return new ProductB1();}
};
class ConcreteFactory2 : public AbstractFactory
{
public:
AbstractProductA* CreateProduceA() {return new ProductA2();}
AbstractProductB* CreateProduceB() {return new ProductB2();}
};
//Client
class Client
{
private:
AbstractProductA* a;
AbstractProductB* b;
public:
Client(AbstractFactory* fac)
{
a = fac->CreateProduceA();
b = fac->CreateProduceB();
}
~Client(){}
void operation()
{
a->operationA();
b->operationB();
}
};
int main()
{
AbstractFactory* fac1 = new ConcreteFactory1();
Client c1(fac1);
c1.operation();
cout << endl;
AbstractFactory* fac2 = new ConcreteFactory2();
Client c2(fac2);
c2.operation();
return 0;
}
Builder (생성 패턴)
다른 특성의 객체를 추가할때 핵심 틀인 추상 클래스(Builder)를 상속받아
쉽게 구성하고 사용하기 위한 패턴
사용시 Director에 생성할 ConcreteBuilder를 넣어 객체를 구성하고 product를 받는다.
sample]
#include <iostream>
using std::cout;
using std::endl;
//Product
class Product
{
private:
int i;
public:
Product(){}
~Product(){}
void Set(const int i) { this->i=i; }
void Show(){ cout << i << endl; }
};
//Abstract Builder
class Builder
{
protected:
Product* product;
public:
Builder() {}
virtual ~Builder() {}
Product* GetProduct() { return product; }
void CreateProduct() { product = new Product(); }
virtual void BuildPart()=0;
};
//ConcreteBuilder
class ConcreteBuilder1 : public Builder
{
public:
ConcreteBuilder1() : Builder() {}
~ConcreteBuilder1(){}
void BuildPart() { product->Set(11); }
};
class ConcreteBuilder2 : public Builder
{
public:
ConcreteBuilder2() : Builder() {}
~ConcreteBuilder2(){}
void BuildPart() { product->Set(22); }
};
//Director
class Director
{
private:
Builder* builder;
public:
Director() : builder(NULL) {}
~Director() { }
void SetBuilder(Builder* b) { builder = b; }
Product* GetProduct() { return builder->GetProduct(); }
void Construct()
{
builder->CreateProduct();
builder->BuildPart();
}
};
int main()
{
Director director;
ConcreteBuilder1 concBuildelrl1;
director.SetBuilder(&concBuildelrl1);
director.Construct();
Product* product1 = director.GetProduct();
product1->Show();
ConcreteBuilder2 concBuildelrl2;
director.SetBuilder(&concBuildelrl2);
director.Construct();
Product* product2 = director.GetProduct();
product2->Show();
return 0;
}
Factory Method (생성 패턴)
: 자식 클래스에게 인스턴스 생성을 미루는 패턴
sample]
#include <iostream>
using std::cout;
using std::endl;
class Product
{
public:
Product(){}
virtual ~Product(){}
virtual void use() = 0;
};
class ConcreteProduct : public Product
{
private:
int i;
public:
ConcreteProduct(int _i) : i(_i){}
~ConcreteProduct(){}
void use() {cout << i << endl;}
};
class Creator
{
public:
Creator(){}
virtual ~Creator(){}
Product* create(int i)
{
//i에 따라 여러가지 자식 객체 생성
Product* p = createProduct(i);
return p;
}
virtual Product* createProduct(int i) = 0;
};
class ConcreteCreator : public Creator
{
public:
Product* createProduct(int i) { return new ConcreteProduct(i); }
};
int main()
{
Creator* fac = new ConcreteCreator();
Product* p = fac->create(11);
p->use();
return 0;
}
Prototype (생성 패턴)
factory에서 원형 객체들를 미리 생성해 둔 후 생성 요청시 복제(clone)하여 새로운 객체를 돌려준다.
사용하기 좋은 경우 :
생성할 객체가 너무 많거나 클래스 생성이 어려운 경우.
framework와 생성부분을 분리하고 싶은 경우.
sample]
#include <iostream>
#include <map>
#include <string>
using namespace std;
class Prototype
{
public:
Prototype() {}
virtual ~Prototype() {}
virtual Prototype* Clone() const = 0;
virtual void Print() const = 0;
};
class A : public Prototype
{
public:
A(){};
~A(){};
A(const A& cls) {}
A* Clone() const { return new A(*this); }
void Print() const { cout << "class A" << endl;}
};
class B : public Prototype
{
public:
B(){};
~B(){};
B(const B& cls) {}
B* Clone() const { return new B(*this); }
void Print() const { cout << "class B" << endl;}
};
class PrototypeFactory
{
private:
std::map<int, Prototype*> m_map;
public:
PrototypeFactory()
{
m_map[1] = new A();
m_map[2] = new B();
}
Prototype* Create(int type)
{
return m_map[type]->Clone();
}
~PrototypeFactory()
{
delete m_map[1];
delete m_map[2];
m_map.clear();
}
};
int main(void)
{
PrototypeFactory* fac = new PrototypeFactory();
Prototype* a = fac->Create(1);
Prototype* b = fac->Create(2);
a->Print();
b->Print();
delete a;
delete b;
return 0;
}
Singleton (생성 패턴)
유일한 인스턴스 생성시 사용하는 패턴
sample]
//Singleton.h
#pragma once
class CSingleton
{
private:
CSingleton(void);
CSingleton(const CSingleton& logger);
CSingleton& operator=(CSingleton& logger);
public:
~CSingleton(void);
public:
static CSingleton* inst;
static CSingleton& getInstance(void);
static CSingleton* getInstancePtr(void);
static void destroy(void);
};
//Singleton.cpp
#include "Singleton.h"
CSingleton* CSingleton::inst;
CSingleton::CSingleton(void) {}
CSingleton::~CSingleton(void) {}
CSingleton& CSingleton::getInstance(void)
{
if (inst == 0)
inst = new CSingleton;
return *inst;
}
CSingleton* CSingleton::getInstancePtr(void)
{
if (inst == 0)
inst = new CSingleton;
return inst;
}
void CSingleton::destroy(void)
{
if (inst != 0)
{
delete inst;
inst = 0;
}
}
Adapter (Wrapper) (구조 패턴)
호환성 없는 인터페이스간의 동작을 위한 패턴.
요구되는 인터페이스인 Target을 상속하고 호환 시킬 Adaptee를 멤버 변수로 갖는 Adapter 클래스를 생성한다.
Object Adapter : Adaptee를 멤버 변수로 갖는 구조
Class Adapter : Target과 Adaptee를 구현이나 상속으로 갖는 구조
sample : Object Adapter]
#include <iostream>
using std::cout;
using std::endl;
class Target
{
public:
Target(){}
virtual ~Target(){}
virtual void Operation1() = 0;
virtual void Operation2() = 0;
};
class Adaptee
{
public:
void OpAdaptee1() {cout << "OpAdaptee1" << endl;}
void OpAdaptee2() {cout << "OpAdaptee2" << endl;}
};
class Adapter : public Target
{
private:
Adaptee adaptee;
public:
void Operation1() {adaptee.OpAdaptee1();}
void Operation2() {adaptee.OpAdaptee2();}
};
int main()
{
Target* target = new Adapter();
target->Operation1();
target->Operation2();
delete target;
return 0;
}
Bridge (Handle/Body) (구조패턴)
구현층과 추상층을 분리하여 각자 독립적인 변형을 할 수 있게 하는 패턴.
추상층 : 인터페이스, 추상클래스
구현층 : 상속 및 구현 클래스
디자인이 복잡해지는 단점
sample]
#include <windows.h>
#include <iostream>
#include <map>
#include <string>
using namespace std;
//Implementor
class Implementor
{
public:
Implementor(){}
virtual ~Implementor(){}
virtual void Operation(int i) = 0;
};
class ConcreteImplementor1 : public Implementor
{
public:
ConcreteImplementor1(){}
~ConcreteImplementor1(){}
void Operation(int i) {cout << i << endl;}
};
class ConcreteImplementor2 : public Implementor
{
public:
ConcreteImplementor2(){}
~ConcreteImplementor2(){}
void Operation(int i) {cout << i << endl;}
};
//Abstraction
class Abstraction
{
public:
Abstraction(){}
~Abstraction(){}
virtual void Operation() = 0;
};
class RefinedAbstraction : public Abstraction
{
private:
Implementor* impl;
int num;
public:
RefinedAbstraction(Implementor* impl, int num)
{
this->impl = impl;
this->num = num;
}
~RefinedAbstraction(){}
void Operation() {impl->Operation(num);};
};
int main(void)
{
ConcreteImplementor1 c1;
ConcreteImplementor2 c2;
RefinedAbstraction r1(&c1, 1);
RefinedAbstraction r2(&c2, 2);
r1.Operation();
r2.Operation();
return 0;
}
Composite (구조 패턴)
객체들의 관계를 트리 구조로 구성하여 부분-전체 계층을 표현하는 패턴
단일 객체와 복합 객체 동일하게 다룰 수 있다.
sample]
#include <iostream>
#include <vector>
#include <string>
using std::cout;
using std::vector;
using std::string;
class Component
{
public:
virtual void list() const = 0;
virtual ~Component(){};
};
class Leaf : public Component
{
private:
int value;
public:
explicit Leaf(int val) : value(val) {}
void list() const
{
cout << "\t" << value << "\n";
}
};
class Composite : public Component
{
private:
vector <Component*> vec;
string id;
public:
explicit Composite(string id) : id(id) {}
void add(Component *obj)
{
vec.push_back(obj);
}
void list() const
{
cout << id << ":" << "\n";
for (vector<Component*>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
(*it)->list();
}
}
};
int main()
{
Leaf num0(0);
Leaf num1(1);
Leaf num2(2);
Leaf num3(3);
Leaf num4(4);
Composite container1("Container 1");
Composite container2("Container 2");
container1.add(&num0);
container1.add(&num1);
container2.add(&num2);
container2.add(&num3);
container2.add(&num4);
container1.add(&container2);
container1.list();
return 0;
}
Decorator (Wrapper) (구조 패턴)
객체에 서비스나 책임을 동적으로 추가/삭제 할 수 있는 패턴으로
서브 클래스를 사용하는 것 보다 향상된 방법.
객체는 기능을 계층적인 모습으로 갖게 된다.
sample]
#include <iostream>
using std::cout;
using std::endl;
class Component
{
public:
virtual void draw() = 0;
virtual ~Component() {}
};
class ConcreteComponent : public Component
{
private:
int i;
public:
ConcreteComponent( int _i ) : i(_i){}
void draw() {cout << "ConcreteComponent: " << i << endl;}
};
class Decorator : public Component
{
private:
Component* wid;
public:
Decorator(Component* w){wid = w;}
void draw() {wid->draw();}
~Decorator() {delete wid;}
};
class ConcreteDecoratorA : public Decorator {
public:
ConcreteDecoratorA(Component* w) : Decorator(w){}
void draw() {
Decorator::draw();
cout << " ConcreteDecoratorA" << '\n';
}
};
class ConcreteDecoratorB : public Decorator {
public:
ConcreteDecoratorB(Component* w) : Decorator(w){}
void draw() {
Decorator::draw();
cout << " ConcreteDecoratorB" << '\n';
}
};
int main( void ) {
Component* component;
component = new ConcreteComponent(111);
component = new ConcreteDecoratorA(component); //동적 기능 추가
component = new ConcreteDecoratorB(component);
component->draw();
delete component;
return 0;
}
Facade (구조 패턴)
많은 부분을 종합하여 하나의 단순한 인터페이스를 제공하는 패턴
sample]
/* Complex parts */
class CPU {
public void freeze() { ... }
public void jump(long position) { ... }
public void execute() { ... }
}
class Memory {
public void load(long position, byte[] data) { ... }
}
class HardDrive {
public byte[] read(long lba, int size) { ... }
}
/* Facade */
class Computer {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public Computer() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
public void startComputer() {
cpu.freeze();
memory.load(BOOT_ADDRESS, hardDrive.read(BOOT_SECTOR, SECTOR_SIZE));
cpu.jump(BOOT_ADDRESS);
cpu.execute();
}
}
/* Client */
class You {
public static void main(String[] args) {
Computer facade = new Computer();
facade.startComputer();
}
}
Flyweight (구조 패턴)
많은 양의 작은 객체들을 공유하여 저장공단에 대한 효율적인 자원사용을 위한 패턴.
intrinsic(본질적인) 상태와 extrinsic(외래) 상태를 구분한다.
본직적인(intrinsic) 상태: 공유가 가능한 독립적인 정보를 갖는 상태
외래(extrinsic) 상태 : 공유가 불가능한 개별적으로 적용되는 정보를 갖는 상태.
객체를 사용할때 목록에서 객체의 포인터를 받아 사용하는 방식으로 구현.
sample]
#include <windows.h>
#include <iostream>
#include <map>
#include <string>
using namespace std;
class Flyweight
{
public:
Flyweight(){}
virtual ~Flyweight(){}
virtual void Operation(int extrinsicState) = 0;
};
class ConcreteFlyweight : public Flyweight
{
private:
int id;
public:
ConcreteFlyweight(int id) {this->id = id;}
void Operation(int extrinsicState) {cout << "operation " << id << endl;}
};
class UnSharedConcreteFlyweight : public Flyweight
{
private:
int id;
public:
UnSharedConcreteFlyweight(int id) {this->id = id;}
void Operation(int extrinsicState) {cout << "operation " << id << endl;}
};
class FlyweightFactory
{
private:
typedef std::map<int, Flyweight*> Map;
Map m_map;
public:
Flyweight* GetFlyweight(int id)
{
Map::iterator it = m_map.find(id);
if(it == m_map.end())
{
m_map.insert(std::pair<int, Flyweight*>(id, new ConcreteFlyweight(id)));
}
return m_map[id];
}
~FlyweightFactory()
{
Map::iterator it;
for (it=m_map.begin(); it!=m_map.end(); it++)
{
delete it->second;
}
m_map.clear();
}
};
int main(void)
{
FlyweightFactory* fac = new FlyweightFactory();
Flyweight* o11 = fac->GetFlyweight(1);
o11->Operation(1);
Flyweight* o12 = fac->GetFlyweight(1);
o12->Operation(1);
Flyweight* o2 = fac->GetFlyweight(2);
o2->Operation(1);
return 0;
}
Proxy (surrogate) (구조 패턴)
객체 사용시 중간에 대리자를 두어 처리할 수 있는 패턴.
객체를 실제 사용할때 생성하도록 지연 생성을 도와준다.
(ex. 실제 이미지가 필요한 시점에 로딩)
sample]
#include <windows.h>
#include <iostream>
#include <map>
#include <string>
using namespace std;
//interface
class Subject
{
public:
Subject(){}
virtual ~Subject(){}
virtual void Request() = 0;
};
class RealSubject : public Subject
{
private:
int i;
public:
RealSubject(int i)
{
this->i = i++; //이미지 로딩같은 작업
}
~RealSubject(){}
void Request() {cout << "Request() " << i << endl;}
};
class Proxy : public Subject
{
private:
RealSubject* real;
int i;
public:
Proxy(int i) : real(NULL) {this->i = i;}
~Proxy(){delete real;}
void Request()
{
if (real == NULL)
real = new RealSubject(i);
real->Request();
}
};
int main(void)
{
Subject* subject = new Proxy(1);
subject->Request();
delete subject;
return 0;
}
Chain of Responsibility (행위 패턴)
요청을 처리할 객체를 만날 때까지 객체 고리를 따라 요청을 전달하는 패턴
요청과 처리에 대한 객체의 결합도를 없애려는 목적의 패턴이다.
굳이 chain 형식보단 vector나 list에 넣고 호출하는 방식이 좀 더 미려해 보인다.
sample]
#include <iostream>
using std::cout;
using std::endl;
#include <string>
//Abstract class
class Handler
{
public:
static const int LEVEL1 = 1;
static const int LEVEL2 = 2;
static const int LEVEL3 = 3;
protected:
int level;
private:
Handler* nextHandler;
public:
Handler() : nextHandler(NULL) {}
virtual ~Handler(){}
Handler* setNext(Handler* next) { return this->nextHandler = next; }
void Request(std::string& str, int priority)
{
if (priority <= level) HandleRequest(str);
if (nextHandler != NULL) nextHandler->Request(str, priority);
}
protected:
virtual void HandleRequest(std::string& str) = 0;
};
class ConcreteHandler1 : public Handler
{
public:
ConcreteHandler1(int level) { this->level = level; }
protected:
void HandleRequest(std::string& str) { cout << "ConcreteHandler1 : " << str << endl; }
};
class ConcreteHandler2 : public Handler
{
public:
ConcreteHandler2(int level) { this->level = level; }
protected:
void HandleRequest(std::string& str) { cout << "ConcreteHandler2 : " << str << endl; }
};
int main( void ) {
Handler* h = new ConcreteHandler1(Handler::LEVEL1);
Handler* h1 = h->setNext(new ConcreteHandler2(Handler::LEVEL2));
h->Request(std::string("hi LEVEL1"), Handler::LEVEL1);
cout << "----" << endl;
h->Request(std::string("hi LEVEL2"), Handler::LEVEL2);
delete h;
return 0;
}
Command (Action, Transaction) (행위 패턴)
요청 자체를 객체화하여 파라미터로 넘겨줄 수 있게 하는 패턴
Invoker를 통해 명령을 실행하며 요청 순서를 기록하여 Undo/Redo를 구현할 수 있다.
필요에 따라 별도의 Invoker 없이 사용되기도 한다.
Receiver는 실제 처리를 수행하는 객체이며 ConcreteCommand는 이 Receiver를 받아 처리를 수행한다.
Receiver도 필요에 따라선 별도 정의 없이 ConcreteCommand 안에 직접 정의되기도 한다.
sample]
#include <iostream>
using std::cout;
using std::endl;
#include <vector>
class Receiver
{
public:
void Action1() { cout << "action1" << endl; }
void Action2() { cout << "action2" << endl; }
};
class Command
{
public:
virtual ~Command(){}
virtual void Execute(void) = 0;
};
class ConcreteCommand1 : public Command
{
private:
Receiver* receiver;
public:
ConcreteCommand1(Receiver* receiver) { this->receiver = receiver; }
void Execute() { receiver->Action1(); }
};
class ConcreteCommand2 : public Command
{
private:
Receiver* receiver;
public:
ConcreteCommand2(Receiver* receiver) { this->receiver = receiver; }
void Execute() { receiver->Action2(); }
};
class Invoker
{
private:
std::vector<Command*> commands;
public:
void executeCommand(Command* command)
{
command->Execute();
commands.push_back(command);
}
void undo(void) {if (commands.size() > 1) commands.pop_back();} //undo 샘플
~Invoker() { /*commands의 자원 삭제 필요*/ }
};
int main( void ) {
Receiver receiver;
Command* command1 = new ConcreteCommand1(&receiver);
Command* command2 = new ConcreteCommand2(&receiver);
Invoker invoker;
invoker.executeCommand(command1);
invoker.executeCommand(command2);
return 0;
}
Interpreter (행위 패턴)
컴퓨터 언어의 문장 분석을 위한 패턴으로 객체지향 컴파일러 구현에 많이 사용된다.
즉, 문법 규칙을 클래스로 표현하며 Expression은 composite 패턴으로 구현된다.
sample] 출처 : http://code1009.tistory.com/49
#include <iostream>
using std::cout;
using std::endl;
#include <map>
#include <string>
class Context
{
public:
std::map<std::string, bool> Variables_;
};
class AbstractExpression
{
public:
virtual bool Interpret(Context&) = 0;
};
class TerminalExpression_Variable: public AbstractExpression
{
public:
explicit TerminalExpression_Variable (std::string n) : Name_(n) {}
virtual bool Interpret(Context& context)
{
return context.Variables_[Name_];
}
private:
std::string Name_;
};
class NonterminalExpression_And: public AbstractExpression
{
public:
NonterminalExpression_And (AbstractExpression* p1, AbstractExpression* p2) : Operand1_(p1), Operand2_(p2) {}
virtual bool Interpret(Context& context) {return Operand1_->Interpret(context) && Operand2_->Interpret(context);}
private:
AbstractExpression* Operand1_;
AbstractExpression* Operand2_;
};
class NonterminalExpression_Or: public AbstractExpression
{
public:
NonterminalExpression_Or (AbstractExpression* p1, AbstractExpression* p2) : Operand1_(p1), Operand2_(p2) {}
virtual bool Interpret(Context& context) {return Operand1_->Interpret(context) || Operand2_->Interpret(context);}
private:
AbstractExpression* Operand1_;
AbstractExpression* Operand2_;
};
int main(void)
{
Context context;
context.Variables_["A"] = 1;
context.Variables_["B"] = 1;
context.Variables_["C"] = 0;
TerminalExpression_Variable a("A");
TerminalExpression_Variable b("B");
TerminalExpression_Variable c("C");
NonterminalExpression_Or exp1 (&a, &b);
NonterminalExpression_And exp2 (&exp1, &c);
bool result = exp2.Interpret(context);
std::cout << "result=" << result << std::endl;
return 0;
};
Iterator (Cursor) (행위 패턴)
내부 표현방법을 노출하지 않고 순차적 접근을 제공하는 패턴
STL의 iterator가 대표적인 구현체 입니다.
sample]
#include <iostream>
using std::cout;
using std::endl;
class Iterator;
class Aggregate
{
public:
virtual Iterator* CreateIterator() = 0;
virtual ~Aggregate(){}
};
class ConcreateAggregate : public Aggregate
{
private:
int* datas;
int size;
public:
ConcreateAggregate(int createSize) : size(createSize)
{
datas = new int[size];
for (int i=0; i<size; i++) datas[i] = i;
}
Iterator* CreateIterator();
int* getAt(int index) {return &datas[index];}
int getSize(void) {return size;}
~ConcreateAggregate() {delete datas;}
};
class Iterator
{
public:
virtual int* First(void) = 0;
virtual int* Next(void) = 0;
virtual int* CurrentItem(void) = 0;
virtual ~Iterator(){}
};
class ConcreteIterator : public Iterator
{
private:
ConcreateAggregate* aggregate;
int index;
public:
ConcreteIterator(ConcreateAggregate* aggregate) : index(0)
{
this->aggregate = aggregate;
}
int* First(void)
{
if (aggregate->getSize() > 0)
return aggregate->getAt(0);
return NULL;
}
int* Next(void)
{
if (index+1 < aggregate->getSize()-1)
return aggregate->getAt(++index);
return NULL;
}
int* CurrentItem(void)
{
return aggregate->getAt(index);
}
};
Iterator* ConcreateAggregate::CreateIterator()
{
Iterator* it = new ConcreteIterator(this);
return it;
}
int main( void )
{
ConcreateAggregate* ca = new ConcreateAggregate(10);
Iterator* it = ca->CreateIterator();
printf("%d\n", *(it->First()));
printf("%d\n", *(it->Next()));
printf("%d\n", *(it->Next()));
printf("%d\n", *(it->CurrentItem()));
delete ca;
delete it;
return 0;
}
Mediator (행위 패턴)
Mediator 객체가 제어로직을 갖고 여러 객체들의 상호작용을 중재해 주는 패턴
객체들은 서로에 대해 몰라도 되기 때문에 연관성이 하나의 객체로 분리되는 패턴이다.
sample] 출처 : http://code1009.tistory.com/29
#include <iostream>
using std::cout;
using std::endl;
#include <memory>
class Colleague;
class Mediator
{
public:
virtual void OnNotify(Colleague*){}
virtual ~Mediator(){}
};
class Colleague
{
protected:
Mediator* mediator;
public:
Colleague(Mediator* m) : mediator(m) {}
virtual ~Colleague() {}
virtual void Notify(void) { if(mediator) mediator->OnNotify(this); }
};
class ConcreteColleague1 : public Colleague
{
public:
ConcreteColleague1(Mediator* m) : Colleague(m) {}
void Act1(void) { Notify(); }
};
class ConcreteColleague2 : public Colleague
{
public:
ConcreteColleague2(Mediator* m) : Colleague(m) {}
void Act2(void) { Notify(); }
};
class ConcreteMediator : public Mediator
{
private:
std::auto_ptr<ConcreteColleague1> colleague1;
std::auto_ptr<ConcreteColleague2> colleague2;
public:
void Init(void)
{
colleague1.reset(new ConcreteColleague1(this));
colleague2.reset(new ConcreteColleague2(this));
}
void Run(void)
{
colleague1->Act1();
colleague2->Act2();
}
virtual void OnNotify(Colleague* c)
{
if (c == colleague1.get())
cout << "ConcreteMediator::OnNotify() = colleague1" << endl;
else if (c == colleague2.get())
cout << "ConcreteMediator::OnNotify() = colleague2" << endl;
}
};
int main(void)
{
ConcreteMediator mediator;
mediator.Init();
mediator.Run();
return 0;
};
Memento (Token) (행위 패턴)
객체의 상태를 객체로 기록하여 복구(undo) 가능하게 해주는 패턴
Memento가 객체의 상태를 기억하는 클래스이며
Originator가 상태에 따른 각각의 Memento들을 생성 및 복구를 담당한다.
CareTaker가 Memento의 목록을 관리한다.
sample]
#include <iostream>
using std::cout;
using std::endl;
#include <vector>
class Memento
{
private:
int state;
public:
Memento(int state_) : state(state_) {}
int GetState(void) { return state; }
void SetState(int state_) {this->state = state_;}
};
class Originator
{
private:
int state;
public:
void set(int state_)
{
this->state = state_;
cout << "current state : " << this->state << endl;
}
Memento* CreateMemento(void)
{
return new Memento(state);
}
void SetMemento(Memento* memento) //복구(undo)
{
this->state = memento->GetState();
cout << "current state : " << this->state << endl;
}
};
int main(void)
{
//Caretaker
std::vector<Memento*> caretaker;
Originator originator;
originator.set(1);
originator.set(2);
caretaker.push_back(originator.CreateMemento()); //Memento
originator.set(3);
originator.set(4);
cout << "undo : ";
originator.SetMemento(caretaker[0]); //복구(undo)
for(std::vector<Memento*>::iterator it=caretaker.begin(); it!=caretaker.end(); it++)
delete (*it);
caretaker.clear();
return 0;
};
Observer (Dependent, Publish-Subscribe) (행위 패턴)
1:N의 관련을 갖는 객체 중 한 객체의 상태 변화시
다른 객체들에게 변화를 통보하여 필요한 작업이 자동으로 이루어지도록 하는 패턴
Subject는 Observer의 목록을 갖고 있으며
변경에 따른 통지가 필요할때 Notify()를 통해 ConcreteObserver의 Update()를 호출한다.
(Subject가 진짜 관찰자(Observer)같은데 이름이 왜 이런지 이해가 안간다.)
(Subject는 Observer로.. Observer는 ObserverServant 정도가 어울려 보이는데..)
sample]
#include <iostream>
using std::cout;
using std::endl;
#include <list>
class Observer //interface
{
public:
virtual void Update() = 0;
virtual ~Observer(){}
};
class Subject
{
private:
typedef std::list<Observer*>::iterator iter;
std::list<Observer*> observers;
public:
void Attach(Observer* observer) { observers.push_back(observer); }
void Detach(Observer* observer) { observers.remove(observer); }
void Notify(void) { for(iter it=observers.begin(); it!=observers.end(); it++) (*it)->Update(); }
virtual ~Subject(){}
};
class ConcreteSubject : public Subject
{
private:
int state;
public:
void SetState(int i) {this->state = i; Notify();}
int GetState(void) {return this->state;}
};
class ConcreteObserver1 : public Observer
{
private:
Subject* subject; //상황에 따라 Observer에 둬도 괜찮을 듯
public:
ConcreteObserver1(Subject* subject)
{
this->subject = subject;
subject->Attach(this);
}
void Update()
{
ConcreteSubject* cs = dynamic_cast<ConcreteSubject*>(subject);
cout << (cs->GetState() + 1) << endl;
}
};
class ConcreteObserver2 : public Observer
{
private:
Subject* subject; //상황에 따라 Observer에 둬도 괜찮을 듯
public:
ConcreteObserver2(Subject* subject)
{
this->subject = subject;
subject->Attach(this);
}
void Update()
{
ConcreteSubject* cs = dynamic_cast<ConcreteSubject*>(subject);
cout << (cs->GetState() + 2) << endl;
}
};
int main( void ) {
ConcreteSubject subject;
ConcreteObserver1 observer1(&subject);
ConcreteObserver2 observer2(&subject);
subject.SetState(1);
cout << "--------------" << endl;
subject.Detach(&observer1);
subject.SetState(10);
return 0;
}
State (Object for State) (행위 패턴)
상태에 따라 스스로 행동을 변경할 수 있는 패턴
Context에서의 상태 변경에 따라 연결되는 ConcreteState가 변경되는 패턴이다.
(strategy 패턴과 동일하나 알고리즘이냐 상태이냐의 관점 차이)
상태 변경을 어디서 어떻게 할지가 문제인 패턴
sample]
#include <iostream>
using std::cout;
using std::endl;
class State
{
public:
virtual void Handler() = 0;
virtual ~State(){}
};
class ConcreteStateA : public State
{
public:
void Handler(void) { cout << "ConcreteStateA : ON" << endl;}
};
class ConcreteStateB : public State
{
public:
void Handler(void) { cout << "ConcreteStateB : OFF" << endl;}
};
class Context
{
private:
State* state;
int i;
public:
Context(void) : state(NULL), i(0){}
void Request(void)
{
if (state != NULL)
{
delete state;
state = NULL;
}
if (i++%2 == 0)
state = new ConcreteStateA();
else
state = new ConcreteStateB();
state->Handler();
}
};
int main( void )
{
Context context;
context.Request();
context.Request();
context.Request();
context.Request();
return 0;
}
Strategy (Policy) (행위 패턴)
알고리즘별로 클래스화하여 클라이언트와 독립적인 다양한 알고리즘으로 변형시킬 수 있는 패턴
sample]
#include <iostream>
using std::cout;
using std::endl;
class Strategy
{
public:
virtual void AlgorithmInterface(void) = 0;
virtual ~Strategy() {}
};
class ConcreteStrategyA : public Strategy
{
public:
void AlgorithmInterface(void) { cout << "ConcreteStrategyA algorithm" << endl; }
};
class ConcreteStrategyB : public Strategy
{
public:
void AlgorithmInterface(void) { cout << "ConcreteStrategyB algorithm" << endl; }
};
class ConcreteStrategyC : public Strategy
{
public:
void AlgorithmInterface(void) { cout << "ConcreteStrategyC algorithm" << endl; }
};
class Context
{
private:
Strategy* strategy;
public:
Context(Strategy* strategy) { this->strategy = strategy; }
void ContextInterface() { strategy->AlgorithmInterface(); }
};
int main( void ) {
Context* context;
context = new Context(new ConcreteStrategyA());
context->ContextInterface();
context = new Context(new ConcreteStrategyB());
context->ContextInterface();
context = new Context(new ConcreteStrategyC());
context->ContextInterface();
delete context;
return 0;
}
Template Method (행위 패턴)
부모 클래스의 TemplateMethod에서 실행 구조를 정의하고
서브 클래스에서 TemplateMethod에서 사용하는 메소드를 정의하는 패턴
sample]
#include <iostream>
using std::cout;
using std::endl;
class AbstractClass
{
public:
AbstractClass(){}
virtual ~AbstractClass(){}
void TemplateMethod(void)
{
PrimitiveOperation1();
PrimitiveOperation2();
}
protected:
virtual void PrimitiveOperation1(void) = 0;
virtual void PrimitiveOperation2(void) = 0;
};
class ConcreteClass1 : public AbstractClass
{
protected:
void PrimitiveOperation1(void) { cout << "ConcreteClass1::PrimitiveOperation1()" << endl; }
void PrimitiveOperation2(void) { cout << "ConcreteClass1::PrimitiveOperation2()" << endl; }
};
class ConcreteClass2 : public AbstractClass
{
protected:
void PrimitiveOperation1(void) { cout << "ConcreteClass2::PrimitiveOperation1()" << endl; }
void PrimitiveOperation2(void) { cout << "ConcreteClass2::PrimitiveOperation2()" << endl; }
};
int main( void ) {
AbstractClass* cls;
cls = new ConcreteClass1();
cls->TemplateMethod();
delete cls;
cls = new ConcreteClass2();
cls->TemplateMethod();
delete cls;
return 0;
}
Visitor (행위 패턴)
대상 클래스의 변경 없이 새로운 오퍼레이션을 정의할 수 있는 패턴.
이미 많은 ConcreteElement가 존재하는데 이때 공통된 오퍼레이션을 추가해야 할 경우
추가되는 오퍼레이션을 별도의 클래스(Visitor)로 분리해 낼 수 있는 패턴.
결국, 새로 추가되는 Visitor 자체가 새로운 operation이 된다.
실행 과정은 Visitor가 Element에 방문하면 Element는 자기자신을 Visitor에게 넘겨주고
Visitor는 넘겨받은 Element를 자신의 메소드에서 실행한다.
사실 Visitor 패턴은 Double Dispatch(이중 분리)를 위해 만들어진 트릭 정도의 패턴입니다.
Double Dispatch는 어떤 메소드 호출시 두 가지의 런타임 타입에 의존할 경우 사용되는 메카니즘.
sample]
#include <iostream>
using std::cout;
using std::endl;
class ConcreteElement1;
class ConcreteElement2;
class ConcreteElement3;
class Visitor //interface
{
public:
virtual void VisitConcreteElement(ConcreteElement1* element) = 0;
virtual void VisitConcreteElement(ConcreteElement2* element) = 0;
virtual void VisitConcreteElement(ConcreteElement3* element) = 0;
virtual ~Visitor(){}
};
class Element //interface
{
private:
public:
virtual void Accept(Visitor* visitor) = 0;
virtual ~Element(){}
};
class ConcreteElement1 : public Element
{
public:
void Accept(Visitor* visitor) { visitor->VisitConcreteElement(this); }
};
class ConcreteElement2 : public Element
{
public:
void Accept(Visitor* visitor) { visitor->VisitConcreteElement(this); }
};
class ConcreteElement3 : public Element
{
public:
void Accept(Visitor* visitor) { visitor->VisitConcreteElement(this); }
};
class ConcreteVisitor1 : public Visitor
{
public:
void VisitConcreteElement(ConcreteElement1* element) {cout << "new operation : ConcreteVisitor1-ConcreteElement1" << endl;}
void VisitConcreteElement(ConcreteElement2* element) {cout << "new operation : ConcreteVisitor1-ConcreteElement2" << endl;}
void VisitConcreteElement(ConcreteElement3* element) {cout << "new operation : ConcreteVisitor1-ConcreteElement3" << endl;}
};
class ConcreteVisitor2 : public Visitor
{
public:
void VisitConcreteElement(ConcreteElement1* element) {cout << "new operation : ConcreteVisitor2-ConcreteElement1" << endl;}
void VisitConcreteElement(ConcreteElement2* element) {cout << "new operation : ConcreteVisitor2-ConcreteElement2" << endl;}
void VisitConcreteElement(ConcreteElement3* element) {cout << "new operation : ConcreteVisitor2-ConcreteElement3" << endl;}
};
int main( void )
{
//ObjectStructure : Element
Element* elements[] = {new ConcreteElement1(), new ConcreteElement2(), new ConcreteElement3()};
ConcreteVisitor1 visitor1;
ConcreteVisitor2 visitor2;
for (int i=0; i<3; i++) elements[i]->Accept(&visitor1);
cout << "---------------" << endl;
for (int i=0; i<3; i++) elements[i]->Accept(&visitor2);
for (int i=0; i<3; i++) delete elements[i];
return 0;
}
'C++' 카테고리의 다른 글
SEH (Structured Exception Handling) 예외처리 (0) | 2011.01.12 |
---|---|
윈도우 GUI에서 콘솔(console) 띄우기 (0) | 2011.01.11 |
Windows 접근 제어 (0) | 2011.01.11 |
CRITICAL_SECTION을 사용한 Lock 클래스 예제 (0) | 2011.01.07 |
POSA (Pattern-Oriented Software Architecture) (0) | 2011.01.03 |
ACE (ADAPTIVE Communication Environment) (0) | 2011.01.03 |
UML class 관계 표기법 (1) | 2011.01.03 |
ActiveX Control Test Container : Visual Studio 2008 (0) | 2010.12.09 |