Design Patterns

Материал из Wiki.crossplatform.ru

(Различия между версиями)
Перейти к: навигация, поиск
(Строитель (Builder))
(Добавил деструктор для CObserver)
 
(17 промежуточных версий не показаны.)
Строка 308: Строка 308:
== Создатель экземпляров класса (Creator) ==
== Создатель экземпляров класса (Creator) ==
 +
<source lang="cpp">template <typename TItem>
 +
class CDataStorage
 +
{
 +
private:
 +
    std::vector<TItem*> m_items;
 +
 +
public:
 +
    CDataStorage () {};
 +
    ~CDataStorage ()
 +
    {
 +
        for (auto it = m_items.begin (); it != m_items.end(); ++it)
 +
    delete *it;
 +
    }
 +
 +
    std::size_t createItem ()
 +
    {
 +
        std::size_t item_index = m_items.size ();
 +
        m_items.push_back (new TItem());
 +
        return item_index;
 +
    }
 +
 +
    std::size_t size () const { return m_items.size ();}
 +
    TItem & itemAt (std::size_t index) { return *m_items[index];}
 +
    const TItem & itemAt (std::size_t index) const { return *m_items[index];}
 +
};
 +
 +
int main(int argc, char* argv[])
 +
{
 +
    CDataStorage<int> data;
 +
    data.createItem ();
 +
    data.createItem ();
 +
    int &item1 = data.itemAt (0);
 +
    item1 = 42;
 +
    std::cout << data.itemAt (0);
 +
}</source>
 +
== Строитель (Builder) ==
== Строитель (Builder) ==
<source lang="cpp">#include <string>
<source lang="cpp">#include <string>
#include <iostream>
#include <iostream>
-
class CCode
+
class COs
{
{
private:
private:
-
     std::string m_szLang;
+
    int m_nType;
 +
    int m_nCore;
 +
     std::string m_szName;
public:
public:
-
     void check(){ std::cout << "Check: " << m_szLang << " code" << std::endl; }
+
     void setType( int nType ) { m_nType = nType; }
-
     void compile(const std::string &rLang) { m_szLang = rLang; }
+
     void setCore( int nCore ) { m_nCore = nCore; }
-
     void createByteCode(){ std::cout << "Create byte code for: " << m_szLang << " code" << std::endl; }
+
    void setName( std::string szName ) { m_szName = szName; }
-
    void print() const { std::cout << "Code: " << m_szLang << std::endl; }
+
     void print() { std::cout << "Os type: " << m_nType << " core: " << m_nCore << " name: " << m_szName << std::endl; }
};
};
-
// Abstract Builder
+
class COsBuilder
-
class CCodeBuilder
+
{
{
protected:
protected:
-
     CCode m_code;
+
     COs *m_pOs;
public:
public:
-
     const CCode& code() { return m_code; }
+
     void createNewOs() { m_pOs = new COs(); }
 +
    COs *os() { return m_pOs; }
-
     virtual void compileCode() = 0;
+
     virtual void setOsType() = 0;
-
     virtual void checkCode() = 0;
+
     virtual void setOsCore() = 0;
-
     virtual void createByteCode() = 0;
+
     virtual void setOsName() = 0;
};
};
-
class CPythonBuilder : public CCodeBuilder {
+
class CLinuxBuilder : public COsBuilder {
public:
public:
-
     void compileCode() { m_code.compile("python"); }
+
     void setOsType() { m_pOs->setType( 0 ); }
-
     void checkCode() { m_code.check(); }
+
     void setOsCore() { m_pOs->setCore( 11111 ); }
-
     void createByteCode() { m_code.createByteCode(); }
+
     void setOsName() { m_pOs->setName( "Red hat" ); }
};
};
-
class CJavaBuilder : public CCodeBuilder
+
class CWindowsBuilder : public COsBuilder
{
{
public:
public:
-
     void compileCode() { m_code.compile("java"); }
+
     void setOsType() { m_pOs->setType( 1 ); }
-
     void checkCode() { m_code.check(); }
+
     void setOsCore() { m_pOs->setCore( 22222 ); }
-
     void createByteCode() { m_code.createByteCode(); }
+
     void setOsName() { m_pOs->setName( "Windows 8" ); }
};
};
-
class CDeveloper
+
class CSysAdmin
{
{
private:
private:
-
     CCodeBuilder *m_pCodeBuilder;
+
     COsBuilder *m_pBuilder;
public:
public:
-
     CDeveloper(): m_pCodeBuilder(0){}
+
     CSysAdmin(): m_pBuilder(0){}
-
     virtual ~CDeveloper() { freeCodeBuilder(); }
+
     virtual ~CSysAdmin() { freeBuilder(); }
-
     void freeCodeBuilder()
+
     void freeBuilder()
     {
     {
-
         if( m_pCodeBuilder )
+
         if( m_pBuilder )
         {
         {
-
             delete m_pCodeBuilder;
+
             delete m_pBuilder;
-
             m_pCodeBuilder = 0;
+
             m_pBuilder = 0;
         }
         }
     }
     }
-
 
+
     void setBuilder(COsBuilder* pBuilder)
-
     void setCodeBuilder(CCodeBuilder* pCodeBuilder)
+
     {
     {
-
         freeCodeBuilder();
+
         freeBuilder();
-
         m_pCodeBuilder = pCodeBuilder;
+
         m_pBuilder = pBuilder;
     }
     }
-
    const CCode& getCode() { return m_pCodeBuilder->code(); }
+
     void construct()
-
     void buildProject()
+
     {
     {
-
         m_pCodeBuilder->compileCode();
+
         m_pBuilder->createNewOs();
-
         m_pCodeBuilder->checkCode();
+
         m_pBuilder->setOsType();
-
         m_pCodeBuilder->createByteCode();
+
         m_pBuilder->setOsCore();
 +
        m_pBuilder->setOsName();
     }
     }
 +
 +
    void printOs(){ m_pBuilder->os()->print(); }
};
};
int main()
int main()
{
{
-
     CDeveloper dev;
+
     CSysAdmin sys;
-
     dev.setCodeBuilder(new CPythonBuilder);
+
     sys.setBuilder(new CLinuxBuilder);
-
     dev.buildProject();
+
     sys.construct();
-
     CCode python = dev.getCode();
+
     sys.printOs();
-
    python.print();
+
-
     dev.setCodeBuilder(new CJavaBuilder);
+
     sys.setBuilder(new CWindowsBuilder);
-
     dev.buildProject();
+
     sys.construct();
-
     CCode java = dev.getCode();
+
     sys.printOs();
-
    java.print();
+
}
}
</source>
</source>
Строка 460: Строка 497:
= Структурные паттерны проектирования классов/обьектов =
= Структурные паттерны проектирования классов/обьектов =
== Адаптер (Adapter) ==
== Адаптер (Adapter) ==
 +
<source lang="cpp">class CDisplay {
 +
public:
 +
    void drawMessage (int x, int y, const std::string &message)
 +
    {
 +
        std::cout << "Display at " << x << " " << y << ": " << message << std::endl;
 +
    }
 +
    int width () { return 200; }
 +
    int height () { return 100; }
 +
};
 +
 +
class CDisplayAdapter {
 +
private:
 +
    CDisplay *m_pDisplay;
 +
public:
 +
    CDisplayAdapter (CDisplay *display) { m_pDisplay = display;}
 +
    void message (float x, float y, const std::string &message)
 +
    {
 +
        int display_x = x * m_pDisplay->width ();
 +
        int display_y = y * m_pDisplay->height ();
 +
        m_pDisplay->drawMessage (display_x, display_y, message);
 +
    }
 +
};
 +
 +
int main(int argc, char* argv[])
 +
{
 +
    CDisplay *output = new CDisplay ();
 +
    CDisplayAdapter display_adapter (output);
 +
 +
    display_adapter.message (0.5f, 0.5f, "I'm center!");
 +
}</source>
 +
== Декоратор (Decorator) или Оболочка (Wrapper) ==
== Декоратор (Decorator) или Оболочка (Wrapper) ==
 +
Предназначен для динамического расширения функциональности объекта (добавления дополнительного поведения).
 +
<source lang=cpp>
 +
#include <iostream>
 +
 +
class CWidget
 +
{
 +
public:
 +
    virtual void draw() = 0;
 +
};
 +
 +
class CDialog : public CWidget
 +
{
 +
public:
 +
    void draw(){ std::cout << "Draw CDialog" << std::endl; }
 +
};
 +
 +
class CToolBar : public CWidget
 +
{
 +
    CWidget *m_pWrap;
 +
public:
 +
    CToolBar( CWidget *pWrap ): m_pWrap(pWrap){}
 +
    void draw(){ std::cout << "Draw CToolBar" << std::endl; m_pWrap->draw(); }
 +
};
 +
 +
class CStatusBar : public CWidget
 +
{
 +
    CWidget *m_pWrap;
 +
public:
 +
    CStatusBar( CWidget *pWrap ): m_pWrap(pWrap){}
 +
    void draw(){ m_pWrap->draw(); std::cout << "Draw CStatusBar" << std::endl; }
 +
};
 +
 +
int main( int argc, char **argv)
 +
{
 +
    CWidget *pDlg = new CDialog(); // Диалог без тулбара и статусбара
 +
    pDlg->draw();
 +
 +
    std::cout << std::endl;
 +
 +
    CWidget *pDlgT = new CToolBar( new CDialog() ); // Диалог c тулбаром и без статусбара
 +
    pDlgT->draw();
 +
 +
    std::cout << std::endl;
 +
 +
    CWidget *pDlgTS = new CToolBar( new CStatusBar( new CDialog() ) ); // Диалог c тулбаром и c статусбаром
 +
    pDlgTS->draw();
 +
 +
    return 0;
 +
}
 +
</source>
 +
где, CToolBar и CStatusBar являются декораторами.
 +
 +
Результат:
 +
<source lang=bash>
 +
Draw CDialog
 +
 +
Draw CToolBar
 +
Draw CDialog
 +
 +
Draw CToolBar
 +
Draw CDialog
 +
Draw CStatusBar
 +
</source>
 +
== Заместитель (Proxy) или Суррогат (Surrogate) ==
== Заместитель (Proxy) или Суррогат (Surrogate) ==
 +
Контролирует доступ к другому объекту, перехватывая все вызовы.
 +
<source lang=cpp>
 +
#include <iostream>
 +
#include <string>
 +
 +
class CImage
 +
{
 +
    std::string m_szName;
 +
public:
 +
    CImage(std::string szName):m_szName(szName){}
 +
    void draw(){ std::cout << "Drawing image: " << m_szName << std::endl; }
 +
    void printName()const { std::cout << "CImage::printName" << std::endl; }
 +
};
 +
 +
class CProxyImage
 +
{
 +
    CImage *m_pImage;
 +
    std::string m_szName;
 +
public:
 +
    CProxyImage( std::string szName): m_pImage(0), m_szName(szName){}
 +
    void draw()
 +
    {
 +
        if( !m_pImage )
 +
            m_pImage = new CImage(m_szName);
 +
        m_pImage->draw();
 +
    }
 +
    void printName()const
 +
    {
 +
        if( m_pImage )
 +
        {
 +
            m_pImage->printName();
 +
            return;
 +
        }
 +
        std::cout << "CProxyImage::printName" << std::endl;
 +
    }
 +
};
 +
 +
int main( int argc, char **argv)
 +
{
 +
    CProxyImage image( "testImage.png" );
 +
    image.printName();
 +
    image.draw();
 +
    image.printName();
 +
 +
    return 0;
 +
}</source>В роли прокси тут выступает CProxyImage, который пока не вызван метод рисования картинки обрабатывает все запросы.
 +
 +
Результат:
 +
<source lang=bash>CProxyImage::printName
 +
Drawing image: testImage.png
 +
CImage::printName</source>
 +
== Информационный эксперт (Information Expert) ==
== Информационный эксперт (Information Expert) ==
== Компоновщик (Composite) ==
== Компоновщик (Composite) ==
 +
<source lang="cpp">class CDrawable {
 +
public:
 +
    CDrawable () {};
 +
    virtual ~CDrawable () {};
 +
 +
    virtual void draw () = 0;
 +
};
 +
 +
class CCircle : public CDrawable {
 +
public:
 +
    virtual void draw () { std::cout << "I'm a circle!" << std::endl;}
 +
};
 +
 +
class CRectangle : public CDrawable {
 +
public:
 +
    virtual void draw () { std::cout << "I'm a rectangle!" << std::endl;}
 +
};
 +
 +
class CDrawableGroup : public CDrawable {
 +
private:
 +
    std::list<CDrawable*> m_children;
 +
public:
 +
    CDrawableGroup () {};
 +
    virtual ~CDrawableGroup ()
 +
    {
 +
        while (!m_children.empty ()) {
 +
            delete m_children.back ();
 +
            m_children.pop_back ();
 +
        };
 +
    };
 +
 +
    void addChild (CDrawable *drawable) { m_children.push_back (drawable); };
 +
    void removeChild (CDrawable *drawable)
 +
    {
 +
        m_children.remove (drawable);
 +
        delete drawable;
 +
    };
 +
 +
    virtual void draw () {
 +
        for (auto it = m_children.begin (); it != m_children.end (); ++it)
 +
    (*it)->draw ();
 +
    };
 +
};
 +
 +
int main(int argc, char* argv[])
 +
{
 +
    CDrawableGroup figures;
 +
    figures.addChild (new CCircle ());
 +
 +
    CDrawableGroup *rect_group = new CDrawableGroup ();
 +
    rect_group->addChild (new CRectangle ());
 +
    rect_group->addChild (new CRectangle ());
 +
    figures.addChild (rect_group);
 +
    figures.draw ();
 +
}</source>
 +
== Мост (Bridge), Handle (описатель) или Тело (Body) ==
== Мост (Bridge), Handle (описатель) или Тело (Body) ==
 +
<source lang="cpp">
 +
#include <iostream>
 +
 +
class CWindowImp
 +
{
 +
public:
 +
    virtual void drawWindow() = 0;
 +
};
 +
 +
class CLinuxWindow : public CWindowImp
 +
{
 +
    void drawWindow() { std::cout << "Draw linux window" << std::endl; }
 +
};
 +
 +
class CWinWindow : public CWindowImp
 +
{
 +
    void drawWindow() { std::cout << "Draw Windows window" << std::endl; }
 +
};
 +
 +
class CMacWindow : public CWindowImp
 +
{
 +
    void drawWindow() { std::cout << "Draw Mac window" << std::endl; }
 +
};
 +
 +
class CWindowFactory
 +
{
 +
public:
 +
    enum TYPES
 +
    {
 +
        LINUX = 0,
 +
        WINDOWS,
 +
        MAC
 +
    };
 +
 +
    // будем считать, что у нас фабрика синглтон и все нормально с освобождением памяти... :)
 +
    static CWindowImp *getWindowImp( CWindowFactory::TYPES type )
 +
    {
 +
        switch( type )
 +
        {
 +
        case LINUX: return new CLinuxWindow();
 +
            break;
 +
        case WINDOWS: return new CWinWindow();
 +
            break;
 +
        case MAC: return new CMacWindow();
 +
            break;
 +
        }
 +
        return 0;
 +
    }
 +
 +
    static CWindowImp *makeWindow()
 +
    {
 +
        // Будем считать, что мы узнали какая у нас ОС
 +
        return getWindowImp(CWindowFactory::LINUX);
 +
    }
 +
};
 +
 +
class CWindow
 +
{
 +
public:
 +
    void draw(){ getWindowImp()->drawWindow(); }
 +
    CWindowImp *getWindowImp(){ return CWindowFactory::makeWindow(); }
 +
};
 +
 +
int main()
 +
{
 +
    CWindow win;
 +
    win.draw();
 +
}</source>
 +
== Низкая связанность (Low Coupling) ==
== Низкая связанность (Low Coupling) ==
== Приспособленец (Flyweight) ==
== Приспособленец (Flyweight) ==
Строка 475: Строка 784:
== Команда (Command), Действие (Action) или Транзакция (Транзакция) ==
== Команда (Command), Действие (Action) или Транзакция (Транзакция) ==
== Наблюдатель (Observer), Опубликовать - подписаться (Publish - Subscribe) или Delegation Event Model ==
== Наблюдатель (Observer), Опубликовать - подписаться (Publish - Subscribe) или Delegation Event Model ==
 +
<source lang="cpp">
 +
#include <iostream>
 +
#include <vector>
 +
#include <algorithm>
 +
 +
class CObserver;
 +
 +
class CModel
 +
{
 +
std::vector<CObserver*> m_views;
 +
int m_nValue;
 +
public:
 +
void attach(CObserver *po) { m_views.push_back( po ); }
 +
void detach(CObserver *po)
 +
{
 +
std::vector<CObserver*>::iterator iter = std::find( m_views.begin(), m_views.end(), po);
 +
if( iter != m_views.end() )
 +
{
 +
m_views.erase( iter );
 +
}
 +
}
 +
void setValue(int val)
 +
{
 +
m_nValue = val;
 +
notify();
 +
}
 +
int getValue() { return m_nValue; }
 +
void notify();
 +
};
 +
 +
class CObserver
 +
{
 +
    CModel *m_pModel;
 +
public:
 +
    CObserver(CModel *pMod)
 +
    {
 +
        m_pModel = pMod;
 +
        m_pModel->attach(this);
 +
    }
 +
 +
    virtual ~CObserver()
 +
    {
 +
        m_pModel.detach(this);
 +
    }
 +
 +
    virtual void update() = 0;
 +
protected:
 +
    CModel *getModel() { return m_pModel; }
 +
};
 +
 +
class CViewDiagram: public CObserver
 +
{
 +
public:
 +
    CViewDiagram(CModel *pMod): CObserver(pMod){}
 +
    void update() { std::cout << "CViewDiagram: " << getModel()->getValue() << std::endl; }
 +
};
 +
 +
class CViewDocument: public CObserver
 +
{
 +
public:
 +
    CViewDocument(CModel *pMod): CObserver(pMod){}
 +
    void update() { std::cout << "CViewDocument: " << getModel()->getValue() << std::endl; }
 +
};
 +
 +
void CModel::notify()
 +
{
 +
for (size_t i = 0; i < m_views.size(); i++)
 +
m_views[i]->update();
 +
}
 +
 +
int main()
 +
{
 +
CModel model;
 +
CViewDocument doc( &model );
 +
CViewDiagram diagr( &model );
 +
 +
for( int n= 0; n < 10; ++n)
 +
{
 +
model.setValue( n );
 +
if( n ==5 )
 +
model.detach( &diagr );
 +
}
 +
}</source>В роли CObserver в данном примере выступают классы виды: CViewDiagram с CViewDocument. Они получают уведомления об изменении в модели.
 +
Вывод:
 +
<source lang="cpp">CViewDocument: 0
 +
CViewDiagram: 0
 +
CViewDocument: 1
 +
CViewDiagram: 1
 +
CViewDocument: 2
 +
CViewDiagram: 2
 +
CViewDocument: 3
 +
CViewDiagram: 3
 +
CViewDocument: 4
 +
CViewDiagram: 4
 +
CViewDocument: 5
 +
CViewDiagram: 5
 +
CViewDocument: 6
 +
CViewDocument: 7
 +
CViewDocument: 8
 +
CViewDocument: 9</source>
 +
== Не разговаривайте с неизвестными (Don't talk to strangers) ==
== Не разговаривайте с неизвестными (Don't talk to strangers) ==
== Посетитель (Visitor) ==
== Посетитель (Visitor) ==
== Посредник (Mediator) ==
== Посредник (Mediator) ==
== Состояние (State) ==
== Состояние (State) ==
 +
<source lang="cpp">#include <iostream>
 +
 +
class CSocket;
 +
class CStateOpen;
 +
class CStateRead;
 +
class CStateClose;
 +
 +
class CState
 +
{
 +
public:
 +
virtual ~CState() {}
 +
 +
virtual void open(CSocket *s) { std::cout << "Already open socket" << std::endl; }
 +
virtual void read(CSocket *s) { std::cout << "Already read socket" << std::endl; }
 +
virtual void close(CSocket *s) { std::cout << "Already close socket" << std::endl; }
 +
};
 +
 +
class CSocket
 +
{
 +
CState *m_pCurrentState;
 +
public:
 +
CSocket();
 +
void setCurrent(CState *p){ m_pCurrentState = p; }
 +
void open() { m_pCurrentState->open(this); }
 +
void read() { m_pCurrentState->read(this); }
 +
void close() { m_pCurrentState->close(this); }
 +
};
 +
 +
class CStateOpen: public CState
 +
{
 +
public:
 +
CStateOpen(){ std::cout << " CStateOpen" << std::endl; }
 +
~CStateOpen(){ std::cout << " ~CStateOpen" << std::endl; }
 +
virtual void read(CSocket *s);
 +
virtual void close(CSocket *s);
 +
};
 +
 +
class CStateRead: public CState
 +
{
 +
public:
 +
CStateRead(){ std::cout << " CStateRead" << std::endl; }
 +
~CStateRead(){ std::cout << " ~CStateRead" << std::endl; }
 +
virtual void open(CSocket *s) { std::cout << " Socket already open..." << std::endl; }
 +
virtual void close(CSocket *s);
 +
};
 +
 +
class CStateClose: public CState
 +
{
 +
public:
 +
CStateClose(){ std::cout << " CStateClose" << std::endl; }
 +
~CStateClose(){ std::cout << " ~CStateClose" << std::endl; }
 +
virtual void open(CSocket *s)
 +
{
 +
std::cout << " Open closing socket" << std::endl;
 +
s->setCurrent( new CStateOpen());
 +
}
 +
virtual void read(CSocket *s) { std::cout << " Error: Don't read closing socket" << std::endl; }
 +
};
 +
 +
CSocket::CSocket()
 +
{
 +
m_pCurrentState = new CStateClose();
 +
}
 +
 +
void CStateOpen::read(CSocket *s)
 +
{
 +
std::cout << " Read socket" << std::endl;
 +
s->setCurrent( new CStateRead());
 +
}
 +
void CStateOpen::close(CSocket *s)
 +
{
 +
std::cout << " Close socket after opening" << std::endl;
 +
s->setCurrent( new CStateClose());
 +
}
 +
 +
void CStateRead::close(CSocket *s)
 +
{
 +
std::cout << " Close socket after reading" << std::endl;
 +
s->setCurrent( new CStateClose());
 +
}
 +
 +
int main()
 +
{
 +
void(CSocket::*ptrs[])() = { &CSocket::open, &CSocket::read, &CSocket::close };
 +
CSocket sock;
 +
int num;
 +
while( 1 )
 +
{
 +
std::cout << "Enter 0/2: ";
 +
std::cin >> num;
 +
(sock.*ptrs[num])();
 +
}
 +
}</source>В данном случае классами состояния являются: CStateOpen, CStateRead и CStateClose. Которые в случае того или иного действия с сокетом меняются...
 +
<source lang="bash">        CStateClose
 +
Enter 0/2: 0
 +
        Open closing socket
 +
        CStateOpen
 +
Enter 0/2: 1
 +
        Read socket
 +
        CStateRead
 +
Enter 0/2: 2
 +
        Close socket after reading
 +
        CStateClose
 +
Enter 0/2: 0
 +
        Open closing socket
 +
        CStateOpen
 +
Enter 0/2: 2
 +
        Close socket after opening
 +
        CStateClose
 +
Enter 0/2: 1
 +
        Error: Don't read closing socket
 +
</source>
 +
== Стратегия (Strategy) ==
== Стратегия (Strategy) ==
== Хранитель (Memento) ==
== Хранитель (Memento) ==
== Цепочка обязанностей (Chain of Responsibility) ==
== Цепочка обязанностей (Chain of Responsibility) ==
== Шаблонный метод (Template Method) ==
== Шаблонный метод (Template Method) ==
 +
<source lang="cpp">#include <iostream>
 +
 +
class CApp
 +
{
 +
public:
 +
void openDocument()
 +
{
 +
//...
 +
doOpenDocument();
 +
//...
 +
}
 +
 +
protected:
 +
virtual void doOpenDocument() { std::cout << "Open simple document" << std::endl; }
 +
};
 +
 +
class CXmlApp: public CApp
 +
{
 +
protected:
 +
void doOpenDocument() { std::cout << "Open XML document" << std::endl; }
 +
};
 +
 +
class CTxtApp: public CApp
 +
{
 +
protected:
 +
void doOpenDocument() { std::cout << "Open TXT document" << std::endl; }
 +
};
 +
 +
int main()
 +
{
 +
CApp *pApps[] = { &CApp(), &CXmlApp(), &CTxtApp() };
 +
for( int n = 0; n < 3; ++n )
 +
pApps[n]->openDocument();
 +
return 0;
 +
}</source>В данном примере метод doOpenDocument является шаблонным методом.
 +
Вывод:
 +
<source lang="bash">Open simple document
 +
Open XML document
 +
Open TXT document</source>
 +
== Высокое зацепление (High Cohesion) ==
== Высокое зацепление (High Cohesion) ==
== Контроллер (Controller) ==
== Контроллер (Controller) ==

Текущая версия на 08:25, 12 февраля 2014

Содержание

[править] Порождающие паттерны проектирования

[править] Абстрактная фабрика (Abstract Factory, Factory), др. название Инструментарий (Kit)

#include <iostream>
 
class CLanguage
{
public:
    virtual void generate() = 0;
};
 
class CPytnon : public CLanguage
{
public:
    void generate() { std::cout << "Generate python code" << std::endl; }
};
 
class CJava : public CLanguage
{
public:
    void generate() { std::cout << "Generate java code" << std::endl; }
};
 
class CLangFactory
{
public:
    virtual CLanguage* createLanguage() = 0;
};
 
class CPythonFactory : public CLangFactory
{
public:
    CLanguage* createLanguage(){ return new CPytnon(); }
};
 
class CJavaFactory : public CLangFactory
{
public:
    CLanguage* createLanguage() { return new CJava(); }
};
 
class CCodeGenerator
{
public:
    CCodeGenerator(CLangFactory* factory)
    {
        CLanguage *pLang = factory->createLanguage();
        pLang->generate();
        delete pLang;
        delete factory;
    }
};
 
CLangFactory* createCodeFactory()
{
    int nLang = -1;
    std::cout << "Enter Language type (0: Python, 1: Java): ";
    std::cin >> nLang;
 
    switch( nLang )
    {
    case 0: return new CPythonFactory();
    case 1: return new CJavaFactory();
    default: std::cout << "Error choice language..." << std::endl; return 0;
    }
}
 
int main()
{
    CLangFactory *plf = createCodeFactory();
    if( plf )
        CCodeGenerator cg( plf );
 
    return 0;
}

[править] Одиночка (Singleton)

[править] Статический

class CSingleton
{
private:
    static CSingleton m_singleton;
 
private:
    CSingleton() {}
    ~CSingleton() {}
    CSingleton(const CSingleton &) {}
    CSingleton & operator=(const CSingleton &) { return *this; }
 
public:
    static CSingleton *instance() { return &m_singleton; }
};
 
CSingleton CSingleton::m_singleton;
 
int main(int , char **)
{
    CSingleton *p = CSingleton::instance();
    // ...
    return 0;
}

[править] Динамический

class CSingleton
{
private:
    static CSingleton *m_pSingleton;
    static int m_nCounter;
 
private:
    CSingleton() {}
    ~CSingleton() {}
    CSingleton(const CSingleton &) {}
    CSingleton & operator=(const CSingleton &) { return *this; }
 
public:
    static CSingleton *instance()
    {
        if( m_nCounter == 0 )
        {
            m_pSingleton = new CSingleton();
        }
        m_nCounter++;
        return m_pSingleton;
    }
    static CSingleton *freeInstance()
    {
        if( m_nCounter > 0 )
        {
            m_nCounter--;
            if( m_nCounter == 0 )
            {
                delete m_pSingleton;
                m_pSingleton = 0;
            }
        }
    }
};
 
CSingleton *CSingleton::m_pSingleton = 0;
int CSingleton::m_nCounter = 0;
 
int main(int , char **)
{
    CSingleton *p = CSingleton::instance();
 
    return 0;
}

[править] Шаблонный

class CClass
{
public:
    virtual ~CClass(){  }
};
 
template <class T>
class CTypedSingleton;
 
template<class T>
class CTypedWrapper : public T, private CTypedSingleton<T>
{
public:
    void operator delete(void *p)
    {
        CTypedSingleton<T>::free();
    }
};
 
template <class T>
class CTypedSingleton
{
    static T* m_self;
    static int m_refcount;
 
protected:
    CTypedSingleton(){}
    CTypedSingleton(const CTypedSingleton&){}
    virtual ~CTypedSingleton(){ m_self = 0; }
    CTypedSingleton &operator=(const CTypedSingleton&){}
 
public:
  static T *init()
  {
      if(!m_self)
          m_self = new CTypedWrapper<T>;
      m_refcount++;
      return m_self;
  }
 
  static void free()
  {
      if( m_refcount > 0)
      {
          --m_refcount;
          if( m_refcount == 0)
          {
              delete m_self;
              m_self = 0;
          }
      }
  }
};
 
template <class T>
T *CTypedSingleton<T>::m_self = 0;
 
template <class T>
int CTypedSingleton<T>::m_refcount = 0;
 
int main(int , char **)
{
    CClass *p = CTypedSingleton<CClass>::init();
    delete p;
 
    return 0;
}

[править] Многопоточный (double-checked locking)

#include <cstdlib>
#include <boost/thread/once.hpp>
 
template <class T>
class Singleton
{
public:
    static T& Instance();
 
private:
    Singleton() {};
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
    virtual ~Singleton() {};
 
    static void Init() { boost::call_once(m_init, &Singleton<T>::InitImpl); }
    static void InitImpl() { m_me = new T; atexit(&Singleton<T>::FreeInstance); }
    static void FreeInstance() { boost::call_once(m_done, &Singleton<T>::FreeImpl); };
    static void FreeImpl() { delete m_me; m_me = NULL; }
    friend int atexit(void (__cdecl *func)(void));
 
private:
    static T* volatile m_me;
    static boost::once_flag m_init, m_done;
};
 
template <class T>
T* Singleton<T>::m_me = NULL;
 
template <class T>
boost::once_flag Singleton<T>::m_init = BOOST_ONCE_INIT;
 
template <class T>
boost::once_flag Singleton<T>::m_done = BOOST_ONCE_INIT;
 
template <class T>
T& Singleton<T>::Instance()
{
      Init();
      return (*m_me);
}

[править] Прототип (Prototype)

#include <iostream>
 
// Прототип
class CPrototype
{
public:
    virtual CPrototype* clone() const = 0;
};
 
// Прототип сайта
class CSitePrototype : public CPrototype
{
private:
    int m_nPages;
 
public:
    CSitePrototype(int nPages) : m_nPages( nPages ){}
    CSitePrototype(const CSitePrototype &r) : m_nPages( r.m_nPages ){}
    virtual CSitePrototype* clone() const { return new CSitePrototype( *this ); }
 
    void setPages(int nPages) { m_nPages = nPages; }
    int getPages() const { return m_nPages; }
    void printPages() const { std::cout << "Pages: " << m_nPages << std::endl; }
};
 
// Клиентская сторона
void clientSide()
{
    CPrototype *pPrototype = new CSitePrototype( 256 );
    for (int n = 0; n < 10; n++)
    {
        CSitePrototype *pSite = static_cast<CSitePrototype*>( pPrototype->clone() );
        pSite->setPages( pSite->getPages() * n );
        pSite->printPages();
        delete pSite;
    }
    delete pPrototype;
    pPrototype = 0;
}
 
int main()
{
    clientSide();
    return 0;
}

[править] Создатель экземпляров класса (Creator)

template <typename TItem>
class CDataStorage 
{
private:
    std::vector<TItem*> m_items;
 
public:
    CDataStorage () {};
    ~CDataStorage () 
    {
        for (auto it = m_items.begin (); it != m_items.end(); ++it)
	    delete *it;
    }
 
    std::size_t createItem () 
    {
        std::size_t item_index = m_items.size ();
        m_items.push_back (new TItem());
        return item_index;
    }
 
    std::size_t size () const { return m_items.size ();}
    TItem & itemAt (std::size_t index) { return *m_items[index];}
    const TItem & itemAt (std::size_t index) const { return *m_items[index];}
};
 
int main(int argc, char* argv[])
{
    CDataStorage<int> data;
    data.createItem ();
    data.createItem ();
    int &item1 = data.itemAt (0);
    item1 = 42;
    std::cout << data.itemAt (0);
}

[править] Строитель (Builder)

#include <string>
#include <iostream>
 
class COs
{
private:
    int m_nType;
    int m_nCore;
    std::string m_szName;
 
public:
    void setType( int nType ) { m_nType = nType; }
    void setCore( int nCore ) { m_nCore = nCore; }
    void setName( std::string szName ) { m_szName = szName; }
    void print() { std::cout << "Os type: " << m_nType << " core: " << m_nCore << " name: " << m_szName << std::endl; }
};
 
class COsBuilder
{
protected:
    COs *m_pOs;
 
public:
    void createNewOs() { m_pOs = new COs(); }
    COs *os() { return m_pOs; }
 
    virtual void setOsType() = 0;
    virtual void setOsCore() = 0;
    virtual void setOsName() = 0;
};
 
class CLinuxBuilder : public COsBuilder {
public:
    void setOsType() { m_pOs->setType( 0 ); }
    void setOsCore() { m_pOs->setCore( 11111 ); }
    void setOsName() { m_pOs->setName( "Red hat" ); }
};
 
class CWindowsBuilder : public COsBuilder
{
public:
    void setOsType() { m_pOs->setType( 1 ); }
    void setOsCore() { m_pOs->setCore( 22222 ); }
    void setOsName() { m_pOs->setName( "Windows 8" ); }
};
 
class CSysAdmin
{
private:
    COsBuilder *m_pBuilder;
 
public:
    CSysAdmin(): m_pBuilder(0){}
    virtual ~CSysAdmin() { freeBuilder(); }
 
    void freeBuilder()
    {
        if( m_pBuilder )
        {
            delete m_pBuilder;
            m_pBuilder = 0;
        }
    }
    void setBuilder(COsBuilder* pBuilder)
    {
        freeBuilder();
        m_pBuilder = pBuilder;
    }
    void construct()
    {
        m_pBuilder->createNewOs();
        m_pBuilder->setOsType();
        m_pBuilder->setOsCore();
        m_pBuilder->setOsName();
    }
 
    void printOs(){ m_pBuilder->os()->print(); }
};
 
int main()
{
    CSysAdmin sys;
 
    sys.setBuilder(new CLinuxBuilder);
    sys.construct();
    sys.printOs();
 
    sys.setBuilder(new CWindowsBuilder);
    sys.construct();
    sys.printOs();
}

[править] Фабричный метод (Factory Method) или Виртуальный конструктор (Virtual Constructor)

#include <iostream>
 
class CDocument
{
public:
    virtual void save() = 0;
};
 
class CWord: public CDocument
{
public:
    void save() { std::cout << "Save word document." << std::endl; }
};
 
class CExcel: public CDocument
{
public:
    void save() { std::cout << "Save excel document." << std::endl; }
};
 
class CApplication
{
    int m_nTypeDocument;
public:
    CApplication( int nTypeDocument ):m_nTypeDocument(nTypeDocument){}
    void setTypeDocument(int nTypeDocument ){ m_nTypeDocument = nTypeDocument; }
 
    void saveFile()
    {
        CDocument *pDoc = getTypeDocument();
        if( pDoc )
            pDoc->save();
    }
 
    CDocument *getTypeDocument()
    {
        switch( m_nTypeDocument )
        {
        case 0: return new CWord();
        case 1: return new CExcel();
        }
        return 0;
    }
};
 
int main()
{
    CApplication app( 0 );
    app.saveFile(); // Word
    app.setTypeDocument( 1 );
    app.saveFile(); // Excel
 
    return 0;
}

[править] Структурные паттерны проектирования классов/обьектов

[править] Адаптер (Adapter)

class CDisplay {
public:
    void drawMessage (int x, int y, const std::string &message) 
    { 
        std::cout << "Display at " << x << " " << y << ": " << message << std::endl;
    }
    int width () { return 200; }
    int height () { return 100; }
};
 
class CDisplayAdapter {
private:
    CDisplay *m_pDisplay;
public:
    CDisplayAdapter (CDisplay *display) { m_pDisplay = display;}
    void message (float x, float y, const std::string &message) 
    {
        int display_x = x * m_pDisplay->width ();
        int display_y = y * m_pDisplay->height ();
        m_pDisplay->drawMessage (display_x, display_y, message);
    }
};
 
int main(int argc, char* argv[])
{
    CDisplay *output = new CDisplay ();
    CDisplayAdapter display_adapter (output);
 
    display_adapter.message (0.5f, 0.5f, "I'm center!");
}

[править] Декоратор (Decorator) или Оболочка (Wrapper)

Предназначен для динамического расширения функциональности объекта (добавления дополнительного поведения).

#include <iostream>
 
class CWidget
{
public:
    virtual void draw() = 0;
};
 
class CDialog : public CWidget
{
public:
    void draw(){ std::cout << "Draw CDialog" << std::endl; }
};
 
class CToolBar : public CWidget
{
    CWidget *m_pWrap;
public:
    CToolBar( CWidget *pWrap ): m_pWrap(pWrap){}
    void draw(){ std::cout << "Draw CToolBar" << std::endl; m_pWrap->draw(); }
};
 
class CStatusBar : public CWidget
{
    CWidget *m_pWrap;
public:
    CStatusBar( CWidget *pWrap ): m_pWrap(pWrap){}
    void draw(){ m_pWrap->draw(); std::cout << "Draw CStatusBar" << std::endl; }
};
 
int main( int argc, char **argv)
{
    CWidget *pDlg = new CDialog(); // Диалог без тулбара и статусбара
    pDlg->draw();
 
    std::cout << std::endl;
 
    CWidget *pDlgT = new CToolBar( new CDialog() ); // Диалог c тулбаром и без статусбара
    pDlgT->draw();
 
    std::cout << std::endl;
 
    CWidget *pDlgTS = new CToolBar( new CStatusBar( new CDialog() ) ); // Диалог c тулбаром и c статусбаром
    pDlgTS->draw();
 
    return 0;
}

где, CToolBar и CStatusBar являются декораторами.

Результат:

Draw CDialog
 
Draw CToolBar
Draw CDialog
 
Draw CToolBar
Draw CDialog
Draw CStatusBar

[править] Заместитель (Proxy) или Суррогат (Surrogate)

Контролирует доступ к другому объекту, перехватывая все вызовы.

#include <iostream>
#include <string>
 
class CImage
{
    std::string m_szName;
public:
    CImage(std::string szName):m_szName(szName){}
    void draw(){ std::cout << "Drawing image: " << m_szName << std::endl; }
    void printName()const { std::cout << "CImage::printName" << std::endl; }
};
 
class CProxyImage
{
    CImage *m_pImage;
    std::string m_szName;
public:
    CProxyImage( std::string szName): m_pImage(0), m_szName(szName){}
    void draw()
    {
        if( !m_pImage )
            m_pImage = new CImage(m_szName);
        m_pImage->draw();
    }
    void printName()const
    {
        if( m_pImage )
        {
            m_pImage->printName();
            return;
        }
        std::cout << "CProxyImage::printName" << std::endl;
    }
};
 
int main( int argc, char **argv)
{
    CProxyImage image( "testImage.png" );
    image.printName();
    image.draw();
    image.printName();
 
    return 0;
}
В роли прокси тут выступает CProxyImage, который пока не вызван метод рисования картинки обрабатывает все запросы.

Результат:

CProxyImage::printName
Drawing image: testImage.png
CImage::printName

[править] Информационный эксперт (Information Expert)

[править] Компоновщик (Composite)

class CDrawable {
public:
    CDrawable () {};
    virtual ~CDrawable () {};
 
    virtual void draw () = 0;
};
 
class CCircle : public CDrawable {
public:
    virtual void draw () { std::cout << "I'm a circle!" << std::endl;}
};
 
class CRectangle : public CDrawable {
public:
    virtual void draw () { std::cout << "I'm a rectangle!" << std::endl;}
};
 
class CDrawableGroup : public CDrawable {
private:
    std::list<CDrawable*> m_children;
public:
    CDrawableGroup () {};
    virtual ~CDrawableGroup () 
    {
        while (!m_children.empty ()) {
            delete m_children.back ();
            m_children.pop_back ();
        };
    };
 
    void addChild (CDrawable *drawable) { m_children.push_back (drawable); };
    void removeChild (CDrawable *drawable) 
    { 
        m_children.remove (drawable);
        delete drawable;		
    };
 
    virtual void draw () {
        for (auto it = m_children.begin (); it != m_children.end (); ++it)
	    (*it)->draw ();
    };
};
 
int main(int argc, char* argv[])
{
    CDrawableGroup figures;
    figures.addChild (new CCircle ());
 
    CDrawableGroup *rect_group = new CDrawableGroup ();
    rect_group->addChild (new CRectangle ());
    rect_group->addChild (new CRectangle ());
    figures.addChild (rect_group);
    figures.draw ();
}

[править] Мост (Bridge), Handle (описатель) или Тело (Body)

#include <iostream>
 
class CWindowImp
{
public:
    virtual void drawWindow() = 0;
};
 
class CLinuxWindow : public CWindowImp
{
    void drawWindow() { std::cout << "Draw linux window" << std::endl; }
};
 
class CWinWindow : public CWindowImp
{
    void drawWindow() { std::cout << "Draw Windows window" << std::endl; }
};
 
class CMacWindow : public CWindowImp
{
    void drawWindow() { std::cout << "Draw Mac window" << std::endl; }
};
 
class CWindowFactory
{
public:
    enum TYPES
    {
        LINUX = 0,
        WINDOWS,
        MAC
    };
 
    // будем считать, что у нас фабрика синглтон и все нормально с освобождением памяти... :)
    static CWindowImp *getWindowImp( CWindowFactory::TYPES type )
    {
        switch( type )
        {
        case LINUX: return new CLinuxWindow();
            break;
        case WINDOWS: return new CWinWindow();
            break;
        case MAC: return new CMacWindow();
            break;
        }
        return 0;
    }
 
    static CWindowImp *makeWindow()
    {
        // Будем считать, что мы узнали какая у нас ОС
        return getWindowImp(CWindowFactory::LINUX);
    }
};
 
class CWindow
{
public:
    void draw(){ getWindowImp()->drawWindow(); }
    CWindowImp *getWindowImp(){ return CWindowFactory::makeWindow(); }
};
 
int main()
{
    CWindow win;
    win.draw();
}

[править] Низкая связанность (Low Coupling)

[править] Приспособленец (Flyweight)

[править] Устойчивый к изменениям (Protected Variations)

[править] Фасад (Facade)

[править] Паттерны проектирования поведения классов/обьектов

[править] Интерпретатор (Interpreter )

[править] Итератор (Iterator) или Курсор (Cursor)

[править] Команда (Command), Действие (Action) или Транзакция (Транзакция)

[править] Наблюдатель (Observer), Опубликовать - подписаться (Publish - Subscribe) или Delegation Event Model

#include <iostream>
#include <vector>
#include <algorithm>
 
class CObserver;
 
class CModel
{
	std::vector<CObserver*> m_views;
	int m_nValue;
public:
	void attach(CObserver *po) { m_views.push_back( po ); }
	void detach(CObserver *po) 
	{ 
		std::vector<CObserver*>::iterator iter = std::find( m_views.begin(), m_views.end(), po); 
		if( iter != m_views.end() )
		{
			m_views.erase( iter );
		}
	}
	void setValue(int val) 
	{ 
		m_nValue = val; 
		notify(); 
	}
	int getValue() { return m_nValue; }
	void notify();
};
 
class CObserver 
{
    CModel *m_pModel;
public:
    CObserver(CModel *pMod) 
    {
        m_pModel = pMod;
        m_pModel->attach(this);
    }
 
    virtual ~CObserver()
    {
        m_pModel.detach(this);
    }
 
    virtual void update() = 0;
protected:
    CModel *getModel() { return m_pModel; }
};
 
class CViewDiagram: public CObserver 
{
public:
    CViewDiagram(CModel *pMod): CObserver(pMod){}
    void update() { std::cout << "CViewDiagram: " << getModel()->getValue() << std::endl; }
};
 
class CViewDocument: public CObserver 
{
public:
    CViewDocument(CModel *pMod): CObserver(pMod){}
    void update() { std::cout << "CViewDocument: " << getModel()->getValue() << std::endl; }
};
 
void CModel::notify()
{
	for (size_t i = 0; i < m_views.size(); i++)
		m_views[i]->update();
}
 
int main() 
{
	CModel model;
	CViewDocument doc( &model );
	CViewDiagram diagr( &model );
 
	for( int n= 0; n < 10; ++n)
	{
		model.setValue( n );
		if( n ==5 )
			model.detach( &diagr );
	}
}
В роли CObserver в данном примере выступают классы виды: CViewDiagram с CViewDocument. Они получают уведомления об изменении в модели.

Вывод:

CViewDocument: 0
CViewDiagram: 0
CViewDocument: 1
CViewDiagram: 1
CViewDocument: 2
CViewDiagram: 2
CViewDocument: 3
CViewDiagram: 3
CViewDocument: 4
CViewDiagram: 4
CViewDocument: 5
CViewDiagram: 5
CViewDocument: 6
CViewDocument: 7
CViewDocument: 8
CViewDocument: 9

[править] Не разговаривайте с неизвестными (Don't talk to strangers)

[править] Посетитель (Visitor)

[править] Посредник (Mediator)

[править] Состояние (State)

#include <iostream>
 
class CSocket;
class CStateOpen;
class CStateRead;
class CStateClose;
 
class CState
{
public:
	virtual ~CState() {}
 
	virtual void open(CSocket *s) { std::cout << "Already open socket" << std::endl; }
	virtual void read(CSocket *s) { std::cout << "Already read socket" << std::endl; }
	virtual void close(CSocket *s) { std::cout << "Already close socket" << std::endl; }
};
 
class CSocket
{
	CState *m_pCurrentState;
public:
	CSocket();
	void setCurrent(CState *p){ m_pCurrentState = p; }
	void open() { m_pCurrentState->open(this); } 
	void read() { m_pCurrentState->read(this); } 
	void close() { m_pCurrentState->close(this); }
};
 
class CStateOpen: public CState
{
public:
	CStateOpen(){ std::cout << "	CStateOpen" << std::endl; }
	~CStateOpen(){ std::cout << "	~CStateOpen" << std::endl; }
	virtual void read(CSocket *s);
	virtual void close(CSocket *s);
};
 
class CStateRead: public CState
{
public:
	CStateRead(){ std::cout << "	CStateRead" << std::endl; }
	~CStateRead(){ std::cout << "	~CStateRead" << std::endl; }
	virtual void open(CSocket *s) { std::cout << "	Socket already open..." << std::endl; }
	virtual void close(CSocket *s);
};
 
class CStateClose: public CState
{
public:
	CStateClose(){ std::cout << "	CStateClose" << std::endl; }
	~CStateClose(){ std::cout << "	~CStateClose" << std::endl; }
	virtual void open(CSocket *s) 
	{ 
		std::cout << "	Open closing socket" << std::endl; 
		s->setCurrent( new CStateOpen()); 
	}
	virtual void read(CSocket *s) { std::cout << "	Error: Don't read closing socket" << std::endl; }
};
 
CSocket::CSocket()
{ 
	m_pCurrentState = new CStateClose(); 
}
 
void CStateOpen::read(CSocket *s) 
{ 
	std::cout << "	Read socket" << std::endl; 
	s->setCurrent( new CStateRead()); 
}
void CStateOpen::close(CSocket *s) 
{ 
	std::cout << "	Close socket after opening" << std::endl; 
	s->setCurrent( new CStateClose()); 
}
 
void CStateRead::close(CSocket *s)
{ 
	std::cout << "	Close socket after reading" << std::endl; 
	s->setCurrent( new CStateClose()); 
}
 
int main()
{
	void(CSocket::*ptrs[])() = { &CSocket::open, &CSocket::read, &CSocket::close };
	CSocket sock;
	int num;
	while( 1 )
	{
		std::cout << "Enter 0/2: ";
		std::cin >> num;
		(sock.*ptrs[num])();
	}
}
В данном случае классами состояния являются: CStateOpen, CStateRead и CStateClose. Которые в случае того или иного действия с сокетом меняются...
        CStateClose
Enter 0/2: 0
        Open closing socket
        CStateOpen
Enter 0/2: 1
        Read socket
        CStateRead
Enter 0/2: 2
        Close socket after reading
        CStateClose
Enter 0/2: 0
        Open closing socket
        CStateOpen
Enter 0/2: 2
        Close socket after opening
        CStateClose
Enter 0/2: 1
        Error: Don't read closing socket

[править] Стратегия (Strategy)

[править] Хранитель (Memento)

[править] Цепочка обязанностей (Chain of Responsibility)

[править] Шаблонный метод (Template Method)

#include <iostream>
 
class CApp
{
public:
	void openDocument() 
	{ 
		//...
		doOpenDocument(); 
		//...
	}
 
protected:
	virtual void doOpenDocument() { std::cout << "Open simple document" << std::endl; }
};
 
class CXmlApp: public CApp
{
protected:
	void doOpenDocument() { std::cout << "Open XML document" << std::endl; }
};
 
class CTxtApp: public CApp
{
protected:
	void doOpenDocument() { std::cout << "Open TXT document" << std::endl; }
};
 
int main()
{
	CApp *pApps[] = { &CApp(), &CXmlApp(), &CTxtApp() };
	for( int n = 0; n < 3; ++n )
		pApps[n]->openDocument();
	return 0;
}
В данном примере метод doOpenDocument является шаблонным методом.

Вывод:

Open simple document
Open XML document
Open TXT document

[править] Высокое зацепление (High Cohesion)

[править] Контроллер (Controller)

[править] Полиморфизм (Polymorphism)

[править] Искусственный (Pure Fabrication)

[править] Перенаправление (Indirection)