Design Patterns

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

(Различия между версиями)
Перейти к: навигация, поиск
(Декоратор (Decorator) или Оболочка (Wrapper): Добавил описание)
(Заместитель (Proxy) или Суррогат (Surrogate))
Строка 594: Строка 594:
== Заместитель (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, который пока не вызван метод рисования картинки обрабатывает все запросы.
 +
== Информационный эксперт (Information Expert) ==
== Информационный эксперт (Information Expert) ==
== Компоновщик (Composite) ==
== Компоновщик (Composite) ==

Версия 12:57, 22 мая 2013

Содержание

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

Абстрактная фабрика (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, который пока не вызван метод рисования картинки обрабатывает все запросы.

Информационный эксперт (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

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

Посетитель (Visitor)

Посредник (Mediator)

Состояние (State)

Стратегия (Strategy)

Хранитель (Memento)

Цепочка обязанностей (Chain of Responsibility)

Шаблонный метод (Template Method)

Высокое зацепление (High Cohesion)

Контроллер (Controller)

Полиморфизм (Polymorphism)

Искусственный (Pure Fabrication)

Перенаправление (Indirection)