Design Patterns
Материал из Wiki.crossplatform.ru
(Различия между версиями)
ViGOur (Обсуждение | вклад) (→Декоратор (Decorator) или Оболочка (Wrapper)) |
ViGOur (Обсуждение | вклад) (→Декоратор (Decorator) или Оболочка (Wrapper): Добавил описание) |
||
Строка 529: | Строка 529: | ||
== Декоратор (Decorator) или Оболочка (Wrapper) == | == Декоратор (Decorator) или Оболочка (Wrapper) == | ||
+ | Предназначен для динамического расширения функциональности объекта (добавления дополнительного поведения). | ||
<source lang=cpp> | <source lang=cpp> | ||
#include <iostream> | #include <iostream> | ||
Строка 577: | Строка 578: | ||
return 0; | return 0; | ||
} | } | ||
+ | </source> | ||
+ | где, CToolBar и CStatusBar являются декораторами. | ||
+ | |||
+ | Результат: | ||
+ | <source lang=bash> | ||
+ | Draw CDialog | ||
+ | |||
+ | Draw CToolBar | ||
+ | Draw CDialog | ||
+ | |||
+ | Draw CToolBar | ||
+ | Draw CDialog | ||
+ | Draw CStatusBar | ||
</source> | </source> | ||
Версия 09:21, 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)
Информационный эксперт (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(); }