一、面向对象设计原则
依赖倒置原则(DIP)
高层模块(稳定)不应该依赖(编译时依赖)于底层模块(变化),二者都应该依赖于抽象(稳定)。
抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。
开放封闭原则
对拓展开放,对更改封闭
类模块是可扩展的,但是不可修改。
单一职责原则(SRP)
一个类应该仅有一个引起它变化的原因。
变化的方向隐含着类的责任。
Liskov替换原则(LSP)
子类必须能够替换它们的基类(IS-A)。
继承表达类型抽象
接口隔离原则(ISP)
不应该强迫客户程序依赖它们不用的方法。
接口应该小而完备。
优先使用组合而不是继承
类继承通常为“白箱复用”,对象组合通常为“黑箱复用”。
继承在某种程度上破坏了封装性,子类父类耦合度高。
对象组合则只要求被组合的对象具有良好的定义的接口,耦合度低。
封装变化点
使用封装来创建对象之间的分界层,让设计者可以对分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。
针对接口编程,而不是针对实现编程
不将变量类型声明为某个特定的具体类,而是声明为某个接口。
客户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案。
二、模板方法
Motivation: 如何在确定稳定操作结构的前提下,灵活应对各个子步骤的变化或者晚期实现需求?
Definition: 定义一个操作中的算法骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义overeide该算法的某些特定步骤。
Case1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Lib {public : void step1 () {} void step3 () {} void step5 () {} };class App {public : bool step2 () {} void step4 () {} };int main () { Lib lib () ; App app () ; lib.step1 (); if (app.step2 ()) { lib.step3 (); } for (int i = 0 ; i < 4 ; ++ i) { app.step4 (); } lib.step5 (); return 0 ; }
Case2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Lib {public : void run () { step1 (); if (step2 ()) { step3 (); } for (int i = 0 ; i < 4 ; ++ i) { step4 (); } step5 (); } virtual ~Lib (){}protected : void step1 () {} void step3 () {} void step5 () {} virtual bool step2 () {} virtual void step4 () {} };class App : public Lib{protected : virtual bool step2 () = 0 ; virtual void step4 () = 0 ; };int main () { Lib* lib = new App (); lib->run (); delete lib; return 0 ; }
Conclution:
- Make it a habit to recognize which function is variable and which is stable. - Template method is common. - The virtual functions are often set to protected.
三、策略模式
Motivaiton: 某些对象的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使的对象很复杂。
Definition: 定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换(变化)。该模式使得算法可以独立于使用它的客户程序(稳定)而变化(拓展,子类化)。
Case1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 enum TaxBase { CN_Tax, US_Tax, DE_Tax, };class SalesOrder { TaxBase tax;public : double CalculateTax () { if (tax == CN_Tax) {} else if (tax == US_Tax) {} else if (tax == DE_Tax) {} } }
Case2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class TaxStrategy {public : virtual double Calculate (const Context& context) = 0 ; virtual ~TaxStrategy () {} }class CNTax : public TaxStrategy {public : virtual double Calculate (const Context& context) {} };class USTax : public TaxStrategy {public : virtual double Calculate (const Context& context) {} };class DETax : public TaxStrategy {public : virtual double Calculate (const Context& context) {} };class SalesOrder {private : TaxStrategy* strategy;public : SalesOrder (StrategyFactory* strategyFactory) { this ->strategy = strategyFactory->NewStrategy (); } ~SalesOrder (){ delete this ->strategy; } double CalculateTax () { Context conttext () ; double val = strategy->Calculate (context); } }
Conclusion:
Strategy pattern provides a series of re-used algorithms to make switching alogrithms more convenient.
Strategy pattern can substitude condition statement unless the conditions are countable.
Single instance pattern can be used to reduce overhead
四、观察者模式
Motivation: - 为某些对象简历通知依赖关系,即,一个对象的状态发生改变,所有的依赖对象都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。 - 使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系,从而实现软件体系结构的松耦合。
Definition: 定义对象间的一对多(变化)的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
Case1: Betray DIP, and the progressBar might be changed with aternaltive form in the future.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class FileSplitter { string m_filePath; int m_fileNumber; ProgressBar* m_progressBar; public : FileSplitter (const string & filePath, int fileNumber, ProgressBar* progressBar) : m_filePath (filePath), m_fileNumber (fileNumber), m_progressBar (progressBar) {} void split () { for (int i = 0 ; i < m_fileNumber; ++i) { if (m_progressBar) { m_progressBar->setValue ((i + 1 ) / m_fileNumber); } } } }class MainForm : public Form { TextBox* txtFilePath; TextBox* txtFileNumber; ProgressBar* progressBar; public : void Button1_Click () { string filePath = txtFilePath->getText (); int number = atoi (txtFileNumber->getText ().c_str ()); FileSplitter splitter (filePath, number, progressBar) ; splitter.split (); } }
Case2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 class IProgress {public : virtual void DoProgress (float value) = 0 ; virtual ~IProgress (){} }class FileSplitter { string m_filePath; int m_fileNumber; list<IProgress*> m_iprogressList; public : FileSplitter (const string & filePath, int fileNumber) : m_filePath (filePath), m_fileNumber (fileNumber) {} void add_IProgress (IProgress* iprogress) { m_iprogressList.add (iprogress); } void remove_IProgress (IProgress* iprogress) { m_iprogressList.remove (iprogress); } void split () { for (int i = 0 ; i < m_fileNumber; ++i) { float progressValue = m_fileNumber; progressValue = (i + 1 ) / progressValue; onProgress (progressValue); } } protected : void onProgress (float value) { for (auto &iter : m_iprogressList) { iter->DoProgress (progressValue); } } };class MainForm : public Form, public IProgress { TextBox* txtFilePath; TextBox* txtFileNumber; ProgressBar* progressBar; public : void Button1_Click () { string filePath = txtFilePath->getText (); int number = atoi (txtFileNumber->getText ().c_str ()); ConsoleNotifier cn; FileSplitter splitter (filePath, number) ; splitter.addIProgress (this ); splitter.addIProgress (&cn); splitter.split (); } virtual void DoProgress (float value) { progressBar->setValue (value); } }class ConsoleNotifier : public IProgress {public : virtual void DoProgress (float value) { cout << "." ; } }
Conclusion:
We can change objective and observer separately with observer pattern to loosen coupling of objective and observer.
目标发送通知时,无需指定观察者,通知会自动传播。
观察者自己决定是否需要订阅通知,目标对象对此一无所知。
五、装饰模式
Motivation: 过度使用继承来拓展对象的功能,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多,各种子类的组合会导致更多子类的膨胀。
Definition: 动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码,减少子类个数)。
Case1: \(1 + n + n * (2^m - 1)\)
其中\((2^m - 1) = C_m^1 + \cdots + C_m^m\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 class Stream {public : virtual char Read (int number) = 0 ; virtual void Seek (int position) = 0 ; virtual void Write (int data) = 0 ; };class FileStream : public Stream {public : virtual char Read (int number) {} virtual char Seek (int position) {} virtual char Write (char data) {} }; class NetworkStream : public Stream {public : virtual char Read (int number) {} virtual char Seek (int position) {} virtual char Write (char data) {} }; class MemoryStream : public Stream {public : virtual char Read (int number) {} virtual char Seek (int position) {} virtual char Write (char data) {} }; class CryptoFileStream : public FileStream {public : virtual char Read (int number) { FileStream::Read (number); } virtual char Seek (int position) { FileStream::Seek (position); } virtual char Write (byte data) { FileStream::Write (data); } }; class CryptoNetworkStream : public NetworkStream {public : virtual char Read (int number) { NetworkStream::Read (number); } virtual char Seek (int position) { NetworkStream::Seek (position); } virtual char Write (byte data) { NetworkStream::Write (data); } }; class CryptoMemoryStream : public MemoryStream {public : virtual char Read (int number) { MemoryStream::Read (number); } virtual char Seek (int position) { MemoryStream::Seek (position); } virtual char Write (byte data) { MemoryStream::Write (data); } }; class BufferedFileStream : public FileStream {};class BufferedNetworkStream : public NetworkStream {};class BufferedMemoryStream : public MemoryStream {};class CryptoBufferedFileStream : public FileSstream {public : virtual char Read (int number) { FileStream::Read (number); } virtual char Seek (int position) { FileStream::Seek (position); } virtual char Write (byte data) { FileStream::Write (data); } }void Process () { CryptoFileStream *fs1 = new CryptoFileStream (); BufferedFileStream *fs2 = new BufferedFileStream (); CryptoBufferedFileStream *fs3 = new CryptoBufferedFileStream (); }
Case2: \(1 + n + 1 + m\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 class Stream {public : virtual char Read (int number) = 0 ; virtual void Seek (int position) = 0 ; virtual void Write (int data) = 0 ; };class FileStream : public Stream {public : virtual char Read (int number) {} virtual char Seek (int position) {} virtual char Write (char data) {} }; class NetworkStream : public Stream {public : virtual char Read (int number) {} virtual char Seek (int position) {} virtual char Write (char data) {} }; class MemoryStream : public Stream {public : virtual char Read (int number) {} virtual char Seek (int position) {} virtual char Write (char data) {} }; DecoratorStream : public Stream {protected : Stream* stream; DecoratorStream (Stream * stm) : stream (stm) {} }class CryptoStream : public DecoratorStream { public : CryptoStream (Stream *stm): DecoratorStream (stm) {} virtual char Read (int number) { stream->Read (number); } virtual char Seek (int position) { stream->Seek (position); } virtual char Write (byte data) { stream->Write (data); } }; class BufferedStream : public DecoratorStream { public : BufferedStream (Stream *stm): DecoratorStream (stm) {} virtual char Read (int number) { stream->Read (number); } virtual char Seek (int position) { stream->Seek (position); } virtual char Write (byte data) { stream->Write (data); } }; void Process () { FileStream* s1 = new FileStream (); CryptoStream* s2 = new CryptoStream (s1); BufferedSteam1* s3 = new BufferedStream (s1); BufferedSteam1* s4 = new BufferedStream (s2); }
Conclusion: - 通过组合而非继承的方法,实现了运行时动态扩展对象功能的能力
六、桥模式
Motivation: 由于某些类型的固有实现逻辑,使得它们具有两个变化的维度,乃至多个维度的变化。
Definition: 将抽象部分与实现部分分离,使他们都可以独立地变化。
Case1: \(1 + n + m * n\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 class Messager {public : virtual void Login (string username, string password) = 0 ; virtual void SendMessage (string message) = 0 ; virtual void SendPicture (Image image) = 0 ; virtual void PlaySound () = 0 ; virtual void DrawShape () = 0 ; virtual void WriteText () = 0 ; virtual void Connect () = 0 ; virtual ~Messager (){} }class PCMessagerBase : public Messager {public : virtual void PlaySound () {} virtual void DrawShape () {} virtual void WriteText () {}; virtual void Connect () {}; }class MobileMessagerBase : public Messager {public : virtual void PlaySound () {} virtual void DrawShape () {} virtual void WriteText () {}; virtual void Connect () {}; }class PCMessagerLite : public PCMessagerBase {public : virtual void Login (string username, string password) { PCMessagerBase::Connect (); } virtual void SendMessage (string message) { PCMessagerBase::WriteText (); } virtual void SendPicture (Image image) { PCMessagerBase::DrawShape (); }; } class PCMessagerPerfect : public PCMessagerBase {public : virtual void Login (string username, string password) { PCMessagerBase::PlaySound (); PCMessagerBase::Connect (); } virtual void SendMessage (string message) { PCMessagerBase::PlaySound (); PCMessagerBase::WriteText (); } virtual void SendPicture (Image image) { PCMessagerBase::PlaySound (); PCMessagerBase::DrawShape (); }; }class MobileMessagerLite : public MobileMessagerBase {public : virtual void Login (string username, string password) { MobileMessagerBase::Connect (); } virtual void SendMessage (string message) { MobileMessagerBase::WriteText (); } virtual void SendPicture (Image image) { MobileMessagerBase::DrawShape (); }; } class MobileMessagerPerfect : public MobileMessagerBase {public : virtual void Login (string username, string password) { MobileMessagerBase::PlaySound (); MobileMessagerBase::Connect (); } virtual void SendMessage (string message) { MobileMessagerBase::PlaySound (); MobileMessagerBase::WriteText (); } virtual void SendPicture (Image image) { MobileMessagerBase::PlaySound (); MobileMessagerBase::DrawShape (); }; }void Process () { Messager *m = new MobileMessagerPerfect (); }
Case2: \(1 + n + 1 + m\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 class Messager {protected : MessagerImp* messagerImp;public : virtual void Login (string username, string password) = 0 ; virtual void SendMessage (string message) = 0 ; virtual void SendPicture (Image image) = 0 ; virtual ~Messager (){} }class MessagerImp {public : virtual void PlaySound () = 0 ; virtual void DrawShape () = 0 ; virtual void WriteText () = 0 ; virtual void Connect () = 0 ; virtual ~MessagerImp (){} }class PCMessagerImp : public MessagerImp {public : virtual void PlaySound () {} virtual void DrawShape () {} virtual void WriteText () {}; virtual void Connect () {}; }class MobileMessagerImp : public MessagerImp {public : virtual void PlaySound () {} virtual void DrawShape () {} virtual void WriteText () {}; virtual void Connect () {}; }class MessagerLite : public Messager { public : virtual void Login (string username, string password) { messagerImp->Connect (); } virtual void SendMessage (string message) { messagerImp->WriteText (); } virtual void SendPicture (Image image) { messagerImp->DrawShape (); }; } class MessagerPerfect : public Messager {public : virtual void Login (string username, string password) { messagerImp->PlaySound (); messagerImp->Connect (); } virtual void SendMessage (string message) { messagerImp->PlaySound (); messagerImp->WriteText (); } virtual void SendPicture (Image image) { messagerImp->PlaySound (); messagerImp->DrawShape (); }; }void Process () { MessagerImp *mImp = new PCMessagerImp (); Messager *m = new MessagerPerfect (mImp); }
Conclusion:
Bridege pattern 使用对象间的组合关系解耦合了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化.
七、工厂方法模式
Motivation:
Definition: 将抽象部分与实现部分分离,使他们都可以独立地变化。
Case1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class ISplitter {public : virtual void split () = 0 ; virtual ~ISplitter (){} };class FileSplitter : public ISplitter{public : void split () { } }class BinarySplitter : public ISplitter{ };class TxtSplitter : public ISplitter{ };class PictureSplitter : public ISplitter{ };class VideoSplitter : public ISplitter{ };class MainForm : public Form {public : void Button1_Click () { string filePath = txtFilePath->getText (); int number = atoi (txtFileNumber->getText ().c_str ()); ISplitter * splitter = new FileSplitter (filePath, number); splitter->split (); } }
Case2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 class SplitterFactory {public : virtual ISplitter* CreateSplitter () = 0 ; virtual ~SplitterFactory () {} };class ISplitter {public : virtual void split () = 0 ; virtual ~ISplitter (){} };class BinarySplitter : public ISplitter{ };class TxtSplitter : public ISplitter{ };class PictureSplitter : public ISplitter{ };class VideoSplitter : public ISplitter{ };class BinarySplitterFactory : public SplitterFactory {public : virtual ISplitter* CreateSplitter () { return new BinarySplitter (); } };class TxtSplitterFactory : public SplitterFactory {public : virtual ISplitter* CreateSplitter () { return new TxtSplitter (); } };class PictureSplitterFactory : public SplitterFactory {public : virtual ISplitter* CreateSplitter () { return new PictureSplitter (); } };class VedioSplitterFactory : public SplitterFactory {public : virtual ISplitter* CreateSplitter () { return new VedioSplitter (); } };class MainForm : public Form { SplitterFactory* factory;public : MianForm (SplitterFactory* factory) { this ->factory = factory; } void Button1_Click () { ISplitter* splitter = factory->CreateSplitter (); splitter->split (); } }
Conclusion:
Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。
Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展的策略,较好地解决了这种紧耦合关系。
Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。
八、抽象工厂模式
Motivation: 在软件系统中,经常面临着一系列相互依赖的对象 的创建工作;同时,由于需求的变化,往往存在更多系统对象的创建工作。
Definition: 提供一个接口,让改接口负责创建一系列“相关或者相互依赖的对象”,无需指定他们具体的类。
Case1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 class IBDConnection { };class IDBConnectionFactory {public : virtual IDBConnection* CreateDBConnection () = 0 ; }class IDBCommand { };class IDBCommandFactory {public : virtual IDBCommand* CreateDBCommand () = 0 ; }class IDataReader { }class IDataReaderFactory {public : virtual IDataReader* CreateIDataReader () = 0 ; }class SqlConnectionFactory : public IDBConnectionFactory{ } class SqlConnection : public IDBConnection{ };class SqlCommandFactory : public IDBCommandFactory{ } class SqlCommand : public IDBCommand{ };class SqlDataReaderFactory : public IDataReaderFactory{ } class SqlDataReader : public IDataReader{ };class OracleConnection : public IDBConnection{ };class OracleCommand : public IDBCommand{ };class OracleDataReader : public IDataReader{ };class EmployeeDAO { IDBConnectionFactory* dbConnectionFactory; IDBCommandFactory* dbCommandFactory; IDataReaderFactory* dataReaderFactory; public : vector<EmployeeDO> GetEmployees () { IDBConnection* connection = IDBConnectionFactory->createDBConnection (); connection->ConnectionString ("..." ); IDBCommand* command = IDBCommandFactory->createDBCommand (); command->CommandText ("..." ); command->SetConnection (connection); IDBDataReader* reader = command->ExecuteReader (); while (reader->Read ()) { } } }
case2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 class IBDConnection { };class IDBCommand { };class IDataReader { }class IDBFactory {public : virtual IDBConnection* CreateDBConnection () = 0 ; virtual IDBCommand* CreateDBCommand () = 0 ; virtual IDataReader* CreateIDataReader () = 0 ; }class SqlDBFactory : public IDBFactory{public : virtual IDBConnection* CreateDBConnection () = 0 ; virtual IDBCommand* CreateDBCommand () = 0 ; virtual IDataReader* CreateIDataReader () = 0 ; } class SqlConnection : public IDBConnection{ };class SqlCommand : public IDBCommand{ };class SqlDataReader : public IDataReader{ };class OracleConnection : public IDBConnection{ };class OracleCommand : public IDBCommand{ };class OracleDataReader : public IDataReader{ };class EmployeeDAO { IDBFactory* dbFactory; public : vector<EmployeeDO> GetEmployees () { IDBConnection* connection = dbFactory->createDBConnection (); connection->ConnectionString ("..." ); IDBCommand* command = dbFactory->createDBCommand (); command->CommandText ("..." ); command->SetConnection (connection); IDBDataReader* reader = command->ExecuteReader (); while (reader->Read ()) { } } }
Conclusion: - 如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂完全可以。
原型模式
Motivation: 在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
Definition: 使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
case 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class ISplitter {public : virtual ISplitter* clone () = 0 ; virtual void split () = 0 ; virtual ~ISplitter (){} };class BinarySplitter : public ISplitter{ virtual ISplitter* clone () { return new BinarySplitter (*this ); } };class TxtSplitter : public ISplitter{ virtual ISplitter* clone () { return new TxtSplitter (*this ); } };class PictureSplitter : public ISplitter{ virtual ISplitter* clone () { return new PictureSplitter (*this ); } };class VideoSplitter : public ISplitter{ virtual ISplitter* clone () { return new VideoSplitter (*this ); } };class MainForm : public Form { ISplitter* prototype; public : MianForm (ISplitter* prototype) { this ->prototype = prototype; } void Button1_Click () { ISplitter* splitter = prototype->clone (); splitter->split (); } }
Conclusion: - 什么时候用原型什么时候用工厂?用工厂模式创建对象是否是几个简单的步骤就能创建出来,还是说要考虑对象复杂的中间状态。 - 原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”。 - 原型模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象--所需工作仅仅是注册一个新类的对象(即原型),然后再任何需要的地方Clone。 - 原型模式中的Clone方法可以利用某些框架中的序列化来实现深拷贝。
构建器
Motivation: 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
单例模式
Motivation:
Definition: 使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
Case1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class Singleton {private : Singleton (); Singleton (const Singlton& other);public : static Singleton* getInstance () ; static Singleton* m_instance; } Singleton* Singleton::m_instance = nullptr ;Sington* Singleton::getInstance () { if (!m_instance) m_instance = new Singleton (); return m_instnace; }Sington* Singleton::getInstance () { Lock lock; if (!m_instance) m_instance = new Singleton (); return m_instnace; }Sington* Singleton::getInstance () { if (!m_instance) { Lock lock; if (!m_instance) m_instance = new Singleton (); } return m_instnace; } std::atomic<Singleton*> Singleton::m_instance; std::mutex Singtle::m_mutex;Singleton* Singleton::getInstance () { Singleton* tmp = m_instance.load (std::memory_order_relaxed); std::atomic_thread_fence (std::memory_order_acquire); if (tmp == nulpptr) { std::lock_guard<std::mutex> lock (m_mutex) ; tmp = m_instance.load (std::memory_oder_relaxed); if (tmp == nullptr ) { tmp = new Singleton; std::atomic_thread_fence (std::memory_order_release); m_instance.store (tmp, std::memory_order_relaxed); } } }
Conclusion: