8.10(금) C++ 디자인패턴 - 정의

from Study/C++ 2007/08/13 16:49 view 28442

1.     오직 한 개만 만들수 있는 객체 -> 싱글톤

2.    
자신의 사본을 만드는 가상함수 -> Prototype

3.    
data의 변화를 여려명에 알려주자 -> Observer, MFC( Doc/View )

4.     기존 클래스의 인터페이스만 변경해서 다른 클래스처럼 보이게 한다.->Adapter, STL stack

5.     그릇은 그릇과 객체를 모두 담을 수 있다. -> Composite ****

6.     객체에 포장을 한다. 포장 후 다시 포장이 가능하다.
      
기본 기능을 하는 객체와 그 기능을 쉽게 사용    할 수 있게 하는 객체가 있다. -> Decorator

7.     객체를 만드는 공장을 짓자. ? Factory

8.     Collection의 모든 요소를 열거하는 객체 -> 반복자

9.     Collection 내부를 떠돌아 다니는 객체 -> Visitor ( 하나씩을 돌아다니며 변경 )

10.   기존 객체를 데신하는 역할의 객체를 만들자 -> Proxy

11.   작고 여러 개 만들어지는 객체는 공유해서 사용하자. -> fly weight

12.   프로그램의 전체 틀을 미리 설계해 놓자. ? Application Framework( 창시자 책 )

13.   책임을 다른 곳에 전달해서 하나의 문제를 여러객체가 처리 할수 있도록 하자.
      책임전가 ? Chain of Responsibility

14.   알고리즘 자체를 캡슐화 하면 변경이 쉬워 진다. ? 전략 패턴

15.   부모에 비가상함수로 알고리즘을 자식에 protected 가상함수로 알고리즘의 구현을 제공하자.
      template method(
메뉴, 아이스크림 )

16.   객체에 사건이 발생시 외부에 전달하는 기법 ? callback, event, signal

Tag | ,

#include <iostream>

#include <memory>

#include <string>

#include <vector>

#include <conio.h>

using namespace std;

using namespace std::tr1;

 

#define interface struct

#define clrscr()  system("cls")

 

//***************************************

//     IMenuHandler

//***************************************

interface IMenuHandler

{

       virtual ~IMenuHandler() {}

       virtual void OnCommand( unsigned int id ) = 0;

};

//***************************************

//     AbstractMenu

//***************************************

class AbstractMenu

{

       string title;

public:

       AbstractMenu( string s) : title(s) {}

       virtual ~AbstractMenu() {}

       virtual string GetTitle() const { return title;}

       virtual void Command() = 0;

};

//***************************************

//     MenuItem

//***************************************

class MenuItem : public AbstractMenu

{

       unsigned int id;

       IMenuHandler* pMenuHandler;

public:

       MenuItem( string s, unsigned int i, IMenuHandler* pHandler)

             : AbstractMenu(s), id(i), pMenuHandler(pHandler) {}

       virtual void Command() { pMenuHandler->OnCommand( id );     }

};

//***************************************

//     PopupMenu

//***************************************

class PopupMenu : public AbstractMenu

{

       typedef shared_ptr<AbstractMenu> PAbstractMenu;

       vector<PAbstractMenu> menu_list;

       bool isroot;

 

       typedef list<Tape*> TapeList;     // 테입 리스트를 명확하게 표현 해준다.

public:

       static string str_exit;

       static string str_goback;

 

       int xpos, ypos; // 현재 팝업 메뉴가 나타 날 위치로 메뉴를 뜨게 해준다.!!

 

public:

       PopupMenu(string s, bool b = false) : AbstractMenu( s ), isroot(b) {}

       void Append(AbstractMenu* m) { menu_list.push_back( (PAbstractMenu)m);}

 

       virtual void Command()

       {

             while( 1 )

             {

                    clrscr();

                    size_t cnt = menu_list.size();

                    for ( size_t i = 0; i < cnt; ++i )

                           cout << i + 1 << ". " <<
                                 menu_list[i]->GetTitle() << endl;

 

                    cout << cnt + 1 << ". " <<
                                 ( isroot ? str_exit:str_goback) << endl;

 

                    unsigned int cmd;

                    cout << "메뉴를선택하세요>> ";

                    cin >> cmd;

 

                    // 문자를 입력 한 경우

                    if ( cin.fail() )

                    {

                           cin.clear();

                           cin.ignore(256, '\n');

                           continue;

                    }

                    if ( cmd < 1 || cmd > cnt + 1 ) continue;

                    if ( cmd == cnt + 1 ) return ;

                    menu_list[cmd-1]->Command();

             }

       }

};

string PopupMenu::str_exit = "종료";

string PopupMenu::str_goback = "이전메뉴로";

 

//---------------------------------------------

// Menu Class 활용 예제..

class VideoShop : public IMenuHandler

{

       shared_ptr<PopupMenu> pMenuBar;         // video shop의 메인 메뉴

public:

       VideoShop() : pMenuBar( new PopupMenu("ROOT", true))

       { }

 

       virtual void OnCommand( unsigned int id )

       {

             cout << id << " 메뉴가선택됨" << endl;

             getch();

       }

 

       void InitMenu()

       {

             // initialize menu

             PopupMenu* p1 = new PopupMenu( "고객관리" );

             p1->Append( new MenuItem( "고객등록", 1, this ));

             p1->Append( new MenuItem( "고객삭제", 2, this ));

             p1->Append( new MenuItem( "기타",      3, this ));

 

             PopupMenu* p2 = new PopupMenu( "Tape 관리" );

             p2->Append( new MenuItem( "Tape 등록", 11, this ));

             p2->Append( new MenuItem( "Tape 삭제", 12, this ));

             p2->Append( new MenuItem( "기타",      13, this ));

            

             PopupMenu* p3 = new PopupMenu( "대여관리" );

             p3->Append( new MenuItem( "대여등록",   21, this ));

             p3->Append( new MenuItem( "반납",       22, this ));

             p3->Append( new MenuItem( "기타",       23, this ));

 

             pMenuBar->Append( p1 );

             pMenuBar->Append( p2 );

             pMenuBar->Append( p3 );

 

             PopupMenu::str_exit = "Exit";

             PopupMenu::str_goback = "Go Back";

       }

 

       void Start()

       {

             InitMenu();

             pMenuBar->Command();

       }

};

 

int main()

{

       VideoShop vs;

       vs.Start();

} 

Tag | ,

8.9(목) C++ 디자인패턴 - Bridge

from Study/C++ 2007/08/13 15:56 view 32472

#include <iostream>

using namespace std;

 

// Bridge 패턴: 인터페이스와 구현을 분리한다.

 

// 모든 MP3 player의 인터페이스

struct MP3PlayImp

{

       virtual void Play() = 0;

       virtual void Stop() = 0;

};

 

// 결국 인터페이스와 구현을 분리하는 개념.

// 사용자는 playstop만 가져다 쓰면 되고

// 제공자는 class만 제공하면 되도록 해야 한다.!!!

// 실제 GUI기능을 갖춘 MP3 Player 클래스

class MP3Play

{

       MP3PlayImp* pImp;

public:

       void Play()

       {

             // 위임(Delegate)라고 한다. - 구현물을 쉽게 바꿀수 있다.

             // PIMP 라는 개념.

             PImp->Play();

       }

 

       void Stop()

       {

             PImp->Stop();

       }

};

 

void main()

{

       // MP3 사용자

       MP3Play p;

       p.Play();

       p.Stop();

}

 


//////////////////////////////////////////////////////////
// linked list
를 만들고 싶다. 값을 추가하는 함수를 만들고 싶다.

// 함수 이름을 무엇으로 할까?

 

// 실제 list의 구현물( 구현의 클래스 )

class real_list

{

public:

       void real_push_front( int a ) { }

       void real_push_back( int a ) { }

};

 

// 내부구현이다른list

class real_list2

{

public:

       void real_push_front( int a )

       {

             //전혀 다른 기법을 사용한다.

       }

       void real_push_back( int a )

       {

             //전혀 다른 기법을 사용한다.

       }

};

 

// 인터페이스 클래스

class list

{

       real_list* st;

public:

       void push_front( int a ) { st->real_push_front(a); }

       void push_back( int a )  { st->real_push_back(a); }

};

 

Tag | ,

#include <iostream>

using namespace std;

 

// FlyWeight 디자인패턴: 작은객체를 공유하는 기법

//               동일한 상태를 가지는 객체는 메모리에 한번만 놓이게 한다.

//               Factory를 사용하게 된다. 또한 Factory는 주로 Sigletone이 된다.

// 객체를 만드는 클래스를 만들어 주자.(생성자를 private로 숨기는 대신)

 

class BigChar

{

       char c;

       BigChar( char a ) : c (a) { }

public:

       void Show() const { cout << "[[[[ " << c << " ]]]]" << endl; }

      

       friend class BigCharFactory;

};

 

#include <map>

 

// BigChar를 생성하는 공장을 만들자.(오직 한 개.싱글톤)

class BigCharFactory

{

       map<char, BigChar*> pool;

       BigCharFactory() {}

 

public:

       static BigCharFactory& GetInstance()

       {

             static BigCharFactory _instance;

             return _instance;

       }

 

       BigChar* CreateBigChar( char c )

       {

             if ( pool[c] == 0 )

                    pool[c] = new BigChar(c);

 

             return pool[c];

       }

 

       void Reset() // 또는 Clean()

       {

             // map에 있는 모든 객체를 제거한다.

       }

 

       void Remove( char c )

       {

       }

};

// Helper Macro 함수

BigChar* CreateChar( char c )

{

       return BigCharFactory::GetInstance().CreateBigChar(c);

}

 

void foo()

{

       BigChar*  p = CreateChar('c');

 

       cout << p << endl;

}

 

void main()

{

       BigChar* p = CreateChar('c');

       cout << p << endl;

 

       foo();

}

Tag | ,

// 방문자( Visitor )를 적용한 버전.

// Accepter가 있어야 한다.

 

#include <iostream>

#include <conio.h>

#include <string>

#include <vector>

using namespace std;

 

#define clrscr()    system("cls")

 

// Acceptor 인터페이스- 모든 방문자를 받아 들일수 있어야 한다.

class IVisitor;

 

struct IAcceptor

{

       virtual void accept( IVisitor* p ) = 0;

};

 

// Visitor 인터페이스- 방문 할수 있어야 한다.

struct IVisitor

{

       virtual void visit( IAcceptor* p ) = 0;

};

 

class AbstractMenu : public IAcceptor

{

       string title;

public:

       AbstractMenu( string s ) : title(s) { }

 

       virtual string GetTitle() const { return title; }

 

       virtual void SetTitle( string s ) { title = s; }

 

       virtual void Command() = 0; // 순수가상함수- 자식은 꼭 만들어야 한다.

 

       virtual void accept( IVisitor* p )

       {

             p->visit( this );          // Visitor 설계의 핵심

       }

};

 

class PopupMenu : public AbstractMenu

{

       vector<AbstractMenu*> menu_list; // Composite

public:

       PopupMenu(string s) : AbstractMenu(s) { }

 

       void Add( AbstractMenu* p ) { menu_list.push_back( p ); }

       void Remove() { }

 

       virtual string GetTitle() const

       {

             return string("[") + AbstractMenu::GetTitle() + string("]");

       }

 

       // 팝업 메뉴가 선택되었을때를 처리한다.

       virtual void Command()

       {

             while(1)

             {

                    // 화면을지우고자신의하위메뉴를열거해준다.

                    clrscr();

 

                    for( int i = 0; i < menu_list.size(); ++i )

                    {

                        cout << i+1 <<"."<< menu_list[i]->GetTitle() <<endl;

                    }

 

                    cout << menu_list.size() + 1 << ". 이전메뉴로" << endl;

                    //------------------------------------------------

                    int cmd;

                    cout << "메뉴를생성하세요>> ";

                    cin >> cmd;

 

                    if ( cmd == menu_list.size()+1 ) // 이전메뉴로 선택

                           break;  // 루프 탈출해서 자신을 이 함수를 마치고

                                   // 자신을 호출한 부분으로 돌아간다.

 

                    // 잘못 선택한 경우
                   
if ( cmd <= 0 || cmd > menu_list.size() )    

                           continue;

 

                    // 해당 메뉴를 실행한다.

                    menu_list[cmd-1]->Command();

             }

       }

 

       // 팝업 메뉴의 경우 모든 항목에 대해 visit를 호출해야 한다.

       virtual void accept( IVisitor* p )

       {

             p->visit( this );   // 먼저 자신을 보내고

            

             for( int i = 0; i < menu_list.size(); ++i )

                    menu_list[i]->accept( p );

       }

};

 

// 메뉴를 처리하고 싶은 모든 클래스는 아래 인터페이스를 구현해야 한다.

struct IMenuHandler

{

       virtual void MenuCommand( int id ) = 0;

};

 

class MenuItem : public AbstractMenu

{

       int id;

       IMenuHandler* pMenuHandler;

public:

       // 부모의 디폴트 생성자가 없으므로 여기서 초기화 해준다.

       MenuItem( string s, int n, IMenuHandler* p )

             : AbstractMenu(s), id(n), pMenuHandler(p) { }

 

       // 메뉴 선택시 처리

       virtual void Command()

       {

             if( pMenuHandler != 0 ) pMenuHandler->MenuCommand( id );

       }

};

 

// 메뉴의 각 항목의 색상을 변경하는 visitor

class RedVisitor : public IVisitor

{

public:

       virtual void visit( IAcceptor* p )

       {

             AbstractMenu* pMenu = (AbstractMenu*)p;

 

             string s = pMenu->GetTitle();

 

             s = s + string("-Red");

 

             pMenu->SetTitle( s );

       }

};

 

//------------------------------------------------------

class VideoShop : public IMenuHandler

{

public:

       void Init()

       {

             PopupMenu* p1 = new PopupMenu("ROOT");

 

             PopupMenu* p2 = new PopupMenu("고객관리");

             PopupMenu* p3 = new PopupMenu("Tape관리");

             PopupMenu* p4 = new PopupMenu("기타");

 

             p1->Add( p2 );

             p1->Add( p3 );

             p1->Add( p4 );

 

             p2->Add( new MenuItem("신규고객등록", 1, this) );

             p2->Add( new MenuItem("고객삭제", 2, this) );

             p2->Add( new MenuItem("기타", 3, this) );

 

             p3->Add( new MenuItem("신규Tape등록", 4, this) );

             p3->Add( new MenuItem("Tape삭제", 5, this) );

             p3->Add( new MenuItem("기타", 6, this) );

 

             RedVisitor r;

             p1->accept(&r);

 

             p1->Command();

       }

 

       void AddCustomer()

       {

             cout << "신규고객등록처리" << endl;

       }

 

       virtual void MenuCommand( int id )

       {

             // 메뉴 ID를 가지고 각 함수로 라우팅 한다.

             if ( id == 1 ) AddCustomer();

 

             cout << "다른ID처리" << endl;

             getch();

       }

};

 

int main()

{

       VideoShop v;

       v.Init();

}

Tag | ,

// 책임의 전가- Chain of reponsibility

// MFCVIEW- DOC - FRAME - APP 로 명령을 넘겨주는 것과 같은 원리..

 

#include <iostream>

#include <conio.h>

#include <string>

#include <vector>

using namespace std;

 

// 메뉴를 처리하고 싶은 모든 클래스는 아래 추상클래스에서 상속되어야 한다.

class IMenuHandler

{

       IMenuHandler* next;

public:

       IMenuHandler() : next(0) {}

 

       // 다음 처리할 객체를 지정한다.

       void SetNext( IMenuHandler* p ) { next = p; }

 

    void MenuCommand( int id )

       {

             // 먼저 자신이 처리를 시동한다.

             if ( Resolve( id ) == false ) // 처리를 못한 경우

             {

                    // 다음으로전달
                   
if ( next != 0 ) next->MenuCommand( id );

             }

       }

protected:

       virtual bool Resolve( int id ) = 0;

};

//-------------------------------------------------------

 

#define clrscr()    system("cls")

 

class AbstractMenu

{

       string title;

public:

       AbstractMenu( string s ) : title(s) { }

 

       virtual string GetTitle() const { return title; }

 

       virtual void Command() = 0;   // 순수가상함수- 자식은 꼭 만들어야 한다.

};

 

class PopupMenu : public AbstractMenu

{

       vector<AbstractMenu*> menu_list; // Composite

public:

       PopupMenu(string s) : AbstractMenu(s) { }

 

       void Add( AbstractMenu* p ) { menu_list.push_back( p ); }

       void Remove() { }
 

       virtual string GetTitle() const

       {

             return string("[") + AbstractMenu::GetTitle() + string("]");

       }

 

       // 팝업메뉴가 선택 되었을때를 처리한다.

       virtual void Command()

       {

             while(1)

             {

                    // 화면을 지우고 자신의 하위메뉴를 열거해준다.

                    clrscr();

 

                    for( int i = 0; i < menu_list.size(); ++i )

                    {

                         cout<<i + 1<<"."<< menu_list[i]->GetTitle() <<endl;

                    }

 

                    cout << menu_list.size() + 1 << ". 이전메뉴로" << endl;

                    //-----------------------------------------------

                    int cmd;

                    cout << "메뉴를 생성하세요>> ";

                    cin >> cmd;

 

                    if ( cmd == menu_list.size()+1 ) // 이전메뉴로 선택

                           break;  // 루프탈출해서 자신을 이 함수를  마치고

                                   // 자신을 호출한 부분으로 돌아간다.

                    // 잘못선택한경우

                    if ( cmd <= 0 || cmd > menu_list.size() )    

                           continue;

 

                    // 해당메뉴를 실행한다.

                    menu_list[cmd-1]->Command();

             }

       }

};

 

// 메뉴를 처리하고 싶은 모든 클래스는 아래 인터페이스를 구현해야 한다.

class MenuItem : public AbstractMenu

{

       int id;

       IMenuHandler* pMenuHandler;

public:

       // 부모의 디폴트 생성자가 없으므로 여기서 초기화 해준다.

       MenuItem( string s, int n, IMenuHandler* p )

             : AbstractMenu(s), id(n), pMenuHandler(p) { }

 

       // 메뉴선택시 처리

       virtual void Command()

       {

             if( pMenuHandler != 0 ) pMenuHandler->MenuCommand( id );

       }

};

//------------------------------------------------------

class TapeList : public IMenuHandler

{

public:

       virtual bool Resolve( int id )

       {

             switch( id )

             {

             case 1: foo(); getch(); return true;

             case 2: foo(); getch(); return true;

             }

             return false;

       }

 

       void foo()

       {

             cout << "TapeList::foo" << endl;

       }

};

 

//-----------------------------------------------------

class VideoShop : public IMenuHandler

{

       TapeList tp_list;

 

public:

       void Init()

       {

             PopupMenu* p1 = new PopupMenu("ROOT");

 

             PopupMenu* p2 = new PopupMenu("고객관리");

             PopupMenu* p3 = new PopupMenu("Tape관리");

             PopupMenu* p4 = new PopupMenu("기타");

 

             p1->Add( p2 );

             p1->Add( p3 );

             p1->Add( p4 );

 

             p2->Add( new MenuItem("신규고객등록", 1, this) );

             p2->Add( new MenuItem("고객삭제", 2, this) );

             p2->Add( new MenuItem("기타", 3, this) );

 

             p3->Add( new MenuItem("신규Tape등록", 4, this) );

             p3->Add( new MenuItem("Tape삭제", 5, this) );

             p3->Add( new MenuItem("기타", 6, this) );

 

             // 메뉴를 처리하고 싶은 다음 객체를 등록시킨다.

             this->SetNext( &tp_list );

 

             p1->Command();

       }

 

       void AddCustomer()

       {

             cout << "신규고객등록처리" << endl;

       }

 

       virtual void MenuCommand( int id )

       {

             // 메뉴ID를 가지고 각 함수로 라우팅한다.

             if ( id == 1 ) AddCustomer();

 

             cout << "다른ID처리" << endl;

             getch();

       }

 

       virtual bool Resolve( int id )

       {

             if ( id == 1 )

             {

                    AddCustomer();

                    return true;

             }

             return false;

       }

};

 

 

int main()

{

       VideoShop v;

       v.Init();

}

Tag | ,

#include <iostream>

#include <conio.h>

#include <string>

#include <vector>

using namespace std;

 

#define clrscr()    system("cls")

 

class AbstractMenu

{

       string title;

public:

       AbstractMenu( string s ) : title(s) { }

 

       virtual string GetTitle() const { return title; }

 

       virtual void Command() = 0; // 순수가상함수- 자식은 꼭 만들어야 한다.

};

 

class PopupMenu : public AbstractMenu

{

       vector<AbstractMenu*> menu_list; // Composite

public:

       PopupMenu(string s) : AbstractMenu(s) { }

 

       void Add( AbstractMenu* p ) { menu_list.push_back( p ); }

       void Remove() {}

 

       virtual string GetTitle() const

       {

             return string("[") + AbstractMenu::GetTitle() + string("]");

       }

 

       // 팝업메뉴가 선택 되었을때를 처리한다.

       virtual void Command()

       {

             while(1)

             {

                    // 화면을 지우고 자신의 하위메뉴를 열거 해준다.

                    clrscr();

 

                    for( int i = 0; i < menu_list.size(); ++i )

                    {

                           cout << i + 1 << "." << menu_list[i]->GetTitle() << endl;

                    }

 

                    cout << menu_list.size() + 1 << ". 이전메뉴로" << endl;

                    //---------------------------------------------------------

                    int cmd;

                    cout << "메뉴를생성하세요>> ";

                    cin >> cmd;

 

                    if ( cmd == menu_list.size()+1 ) // 이전메뉴로 선택

                           break;  // 루프 탈출해서 자신을 이함수를 마치고

                                   // 자신을 호출한 부분으로 돌아간다.

                    // 잘못 선택한 경우

                    if ( cmd <= 0 || cmd > menu_list.size() )
                           continue;

 

                    // 해당메뉴를 실행한다.;;

                    menu_list[cmd-1]->Command();

             }

       }

};

 

// 메뉴를 처리하고 싶은 모든 클래스는 아래 인터페이스를 구현해야 한다.

struct IMenuHandler

{

       virtual void MenuCommand( int id ) = 0;

};

 

class MenuItem : public AbstractMenu

{

       int id;

       IMenuHandler* pMenuHandler;

public:

       // 부모의 디폴트 생성자가 없으므로 여기서 초기화 해준다.

       MenuItem( string s, int n, IMenuHandler* p )

             : AbstractMenu(s), id(n), pMenuHandler(p) { }

 

       // 메뉴선택시 처리

       virtual void Command()

       {

             if( pMenuHandler != 0 ) pMenuHandler->MenuCommand( id );

       }

};

//------------------------------------------------------

class VideoShop : public IMenuHandler

{

public:

       void Init()

       {

             PopupMenu* p1 = new PopupMenu("ROOT");

 

             PopupMenu* p2 = new PopupMenu("고객관리");

             PopupMenu* p3 = new PopupMenu("Tape관리");

             PopupMenu* p4 = new PopupMenu("기타");

 

             p1->Add( p2 );

             p1->Add( p3 );

             p1->Add( p4 );

 

             p2->Add( new MenuItem("신규고객등록", 1, this) );

             p2->Add( new MenuItem("고객삭제", 2, this) );

             p2->Add( new MenuItem("기타", 3, this) );

 

             p3->Add( new MenuItem("신규Tape등록", 4, this) );

             p3->Add( new MenuItem("Tape삭제", 5, this) );

             p3->Add( new MenuItem("기타", 6, this) );

 

             p1->Command();

       }

 

       void AddCustomer()

       {

             cout << "신규고객등록처리" << endl;

       }

 

       virtual void MenuCommand( int id )

       {

             // 메뉴ID를 가지고 각 함수로 라우팅한다.

             if ( id == 1 ) AddCustomer();

 

             cout << "다른ID처리" << endl;

             getch();

       }

};

 

 

int main()

{

       VideoShop v;

       v.Init();

}

 

Tag | ,

8.8(수) C++ 디자인패턴 - Callback

from Study/C++ 2007/08/12 19:53 view 27030

// Callback의 개념.


class Car

{

       typedef void(*SIGNAL)();

       SIGNAL signal;

public:

       Car(SIGNAL s = 0) : signal(s) { }

 

       void SpeedUp( int speed )

       {

             cout << "Speed : " << speed << endl;

 

             if( speed > 100 && signal != 0 )

                    signal();    // 외부에알린다.

       }

};

 

void Police()

{

       cout << "Police Start.." << endl;

}

 

void main()

{

       Car c(Police);

 

       c.SpeedUp(100);

       c.SpeedUp(200);

}

/////////////////////////////////////////////////////////////

// 1. callback을 담당 할 클래스를 만들자. - 함수포인터를 관리하는 객체

class delegate

{

       typedef void(*SIGNAL)();

 

       SIGNAL signal;

       vector<delegate*> del_list;

public:

       delegate( SIGNAL s ) : signal(s) {}

 

       void Add( delegate* p ) { del_list.push_back( p ); }

       void Remove( delegate* p ) { }

      

       void Invoke()

       {

             if( signal != 0 ) signal();

 

             for( int i = 0; i < del_list.size(); ++i )

                    del_list[i]->Invoke();

       }

       // 연산자 재정의

       delegate* operator+=(delegate* p)

       {

             Add(p);

             return this;

       }

 

       void operator()()

       {

             Invoke();

       }

};

//----------------------------------------------------------

 

void foo() { cout << "foo" << endl; }

 

void main()

{

       delegate d1(foo);

       delegate d2(foo);

       delegate d3(foo);

 

       d3 += new delegate(foo);

       d3.Add( new delegate(foo) );

 

       d2 += &d3;

       d1.Add( &d2 );

 

       d1.Invoke();

       cout << endl;

       d1();

}

/////////////////////////////////////////////////////////////////
// 2. callback을 담당 할 클래스를 만들자. - 함수포인터를 관리하는 객체

class delegate

{

       typedef void(*SIGNAL)();

 

       SIGNAL signal;

       vector<delegate*> del_list;

public:

       delegate( SIGNAL s ) : signal(s) {}

 

       void Add( delegate* p ) { del_list.push_back( p ); }

       void Remove( delegate* p ) { }

      

       void Invoke()

       {

             if( signal != 0 ) signal();

 

             for( int i = 0; i < del_list.size(); ++i )

                    del_list[i]->Invoke();

       }

       // 연산자재정의

       delegate* operator+=(delegate* p)

       {

             Add(p);

             return this;

       }

 

       void operator()()

       {

             Invoke();

       }

};

//----------------------------------------------------------

class Car

{

public:

       delegate del;

public:

       Car() : del(0) { }

 

       void SpeedUp( int speed )

       {

             cout << "Speed : " << speed << endl;

 

             if( speed > 100  /*&& del != 0*/ )

                    del(); // 외부에알린다.

       }

};

 

void Police()

{

       cout << "Police Start.." << endl;

}

 

void main()

{

       Car c;

 

       c.del += new delegate(Police);

       c.del += new delegate(Police);

 

       c.SpeedUp(100);

       c.SpeedUp(200);

}

 

 

 

 

 

Tag | ,

8.7(화) C++ 디자인패턴 - Decorator

from Study/C++ 2007/08/08 20:30 view 22659

바닐라 : 1000

딸기   : 1500

초코   : 2000

 

아몬드 : 300

땅콩   : 200

키위   : 500

 

OCP 기능 확장에는 열려 있고 코드 변경에는 닫혀 있도록 해야 한다.

 

Decorator

 

객체(포장대상) - Item(동일 부모) – 포장지( Item& ) 재귀관점!!

cost() : item.cost() + 자신 // 자신을 꾸며서 리턴하므로 Decorator

 

연결. 데코레이터. 감싸주는것. 감싸서 기능을 합쳐준다.!!!!

아이템을 바꾸는건 전략 패턴..

아이템에 힘을 더해주는건 데코레이터 패턴

비행기를 생산하는건 팩토리 패턴..!!



#include <iostream>

using namespace std;

 

// Decorator 패턴:  객체와 포장을 동일하게 다룬다.

 

// Subject와 포장(Decorator)가 가져야 하는 공통의 인터페이스

struct Item

{

        virtual int cost() = 0;

};

 

// Ice Cream 객체.. 대상(Subject).

class Valina: public Item

{

public:

        virtual int cost() { return 1000; }

};

 

class Strawberry: public Item

{

public:

        virtual int cost() { return 1500; }

};

 

class Choko: public Item

{

public:

        virtual int cost() { return 2000; }

};

//----------------------------------------------------

// Decorator 객체들. 내부적으로 Subject의 참조를 가지고 있다.

 

class Almond : public Item

{

        Item& item;

public:

        Almond( Item& i ) : item(i) { }

 

        virtual int cost()

        {

               return item.cost() + 300;

        }

};

 

class Peanut : public Item

{

        Item& item;

public:

        Peanut( Item& i ) : item(i) { }

 

        virtual int cost()

        {

               return item.cost() + 200;

        }

};

 

class Kiwi : public Item

{

        Item& item;

public:

        Kiwi( Item& i ) : item(i) { }

 

        virtual int cost()

        {

               return item.cost() + 500;

        }

};

 

void main()

{

        Valina ice;

 

        Almond a( ice );

        cout << a.cost() << endl;

 

        Peanut p( a );

        cout << p.cost() << endl;

}

 
////////////////////////////////////////////////////

// Decorator의 예 ..
// MFC에서

void main()

{

        int n = 10;

 

        CFile f( "a.txt", CFile::Create );

 

        f.WriteFile( &n );

 

        CArchive ar( &f, CArchive::store );

        ar << n; // ok.

 

        CSocketFile sf;        // 네트워크

        CArchive( &sf, CArchive::store );

        ar2 >> n;

}

Tag | ,

// OCP에 위반된다. 소스변경을 해야 한다.

// Template Method 라고 불리는 디자인설계

// 1. 전체 알고리즘을 부모에게 둔다.(public, 절대가상이아니다.)

// 2. 알고리즘이 사용하는 세부구현은 가상함수로 만들어서 자식이 구현한다.(protected로구현)

 

class IceCream

{

        bool hasPeanut;

        bool hasAlmond;

        bool hasKiwi;

public:

        IceCream( bool b1, bool b2, bool b3 )

               : hasPeanut(b1), hasAlmond(b2), hasKiwi(b3) {}

 

        int cost()

        {

               int s = IceCost();

 

               if( hasPeanut ) s += 200;

               if( hasAlmond ) s += 300;

               if( hasKiwi )   s += 500;

 

               return s;

        }

 

protected:

        // NVI 가상함수를public으로만들지말자.

        virtual int IceCost() = 0;

};

 

class Vanila : public IceCream

{

public:

        Vanila( bool b1, bool b2, bool b3 ) : IceCream( b1, b2, b3 ) {}

        virtual int IceCost() { return 1000; }

};

 

class Strawberry : public IceCream

{

public:

        Strawberry( bool b1, bool b2, bool b3 ) : IceCream( b1, b2, b3 ) {}

        virtual int IceCost() { return 1500; }

};

 

class Choko : public IceCream

{

public:

        Choko( bool b1, bool b2, bool b3 ) : IceCream( b1, b2, b3 ) {}

        virtual int IceCost() { return 2000; }

};

 

void main()

{

        Choko c1( 1, 1, 0 );

 

        cout << c1.cost() << endl;

}

Tag | ,