Design Patterns
Материал из Wiki.crossplatform.ru
(Различия между версиями)
ViGOur (Обсуждение | вклад) (Добавил реализацию паттерна Bridge) |
ViGOur (Обсуждение | вклад) (Добавил деструктор для CObserver) |
||
(14 промежуточных версий не показаны.) | |||
Строка 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> | ||
Строка 461: | Строка 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 | + | <source lang="cpp"> |
#include <iostream> | #include <iostream> | ||
Строка 545: | Строка 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::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 ); } }
Вывод:
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])(); } }
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; }
Вывод:
Open simple document Open XML document Open TXT document