設計模式 c++版(7)——建造者模式
定義:即生成器模式,將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。
示例一:汽車模型擴充套件,根據不同的產品,執行任務的順序不同
1. 類圖說明:
在CarModel 中定義了一個 setSequence 方法,車輛模型的動作如何排布在 ArrayList 中定義。然後 run() 方法根據 sequence 定義的順序完成指定的順序動作
2. 汽車模型,類圖11-1![](https://img-blog.csdn.net/20180921182038265?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0plY2tsaW5fb25saW5l/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
3. 汽車模型,程式碼清單11-1:
//////// ********** 1.車輛模型擴充套件 ,程式碼清單11-1:***************// enum ESequence { EStart , EStop , EAlarm , EEnginBoom }; class CarModel { protected: virtual void start() = 0; virtual void stop() = 0; virtual void alarm() = 0; virtual void enginBoom() = 0; public: void setSequence(QList<ESequence> list){this->m_list = list;} void run() { QList<ESequence>::const_iterator iter = this->m_list.begin(); while(iter != this->m_list.end()) { switch (*iter) { case EStart: this->start(); break; case EStop: this->stop(); break; case EAlarm: this->alarm(); break; case EEnginBoom: this->enginBoom(); break; }; ++iter; } } private: QList<ESequence> m_list; }; class BenzModel:public CarModel { protected: virtual void start() {qDebug() << "BenzModel : start";} virtual void stop() {qDebug() << "BenzModel : stop";} virtual void alarm() {qDebug() << "BenzModel : alarm";} virtual void enginBoom() {qDebug() << "BenzModel : enginBoom";} }; class BMWModel:public CarModel { protected: virtual void start() {qDebug() << "BMWModel : start";} virtual void stop() {qDebug() << "BMWModel : stop";} virtual void alarm() {qDebug() << "BMWModel : alarm";} virtual void enginBoom() {qDebug() << "BMWModel : enginBoom";} }; int main() { CarModel *benz = new BenzModel(); QList<ESequence> list; list.clear(); list.push_back(EEnginBoom); list.push_back(EAlarm); list.push_back(EStart); list.push_back(EStop); benz->setSequence(list); benz->run(); delete benz; return 0; }
示例二:汽車模型擴充套件,增加需求:動作執行順序可以隨意調整
1. 類圖11-2![](https://img-blog.csdn.net/20180921182223805?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0plY2tsaW5fb25saW5l/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
2. 類圖說明:
增加了一個CarBuilder 抽象類,用來組裝各個車模,需要什麼型別什麼順序的車輛模型,都由相關的子類完成。
3. 模板方法模式,程式碼清單11-2:
//////// ********** 2.車輛模型擴充套件 ,程式碼清單11-2:***************// enum ESequence { EStart , EStop , EAlarm , EEnginBoom }; class CarModel { protected: virtual void start() = 0; virtual void stop() = 0; virtual void alarm() = 0; virtual void enginBoom() = 0; public: void setSequence(QList<ESequence> list){this->m_list = list;} void run() { QList<ESequence>::const_iterator iter = this->m_list.begin(); while(iter != this->m_list.end()) { switch (*iter) { case EStart: this->start(); break; case EStop: this->stop(); break; case EAlarm: this->alarm(); break; case EEnginBoom: this->enginBoom(); break; }; ++iter; } } private: QList<ESequence> m_list; }; class BenzModel:public CarModel { protected: virtual void start() {qDebug() << "BenzModel : start";} virtual void stop() {qDebug() << "BenzModel : stop";} virtual void alarm() {qDebug() << "BenzModel : alarm";} virtual void enginBoom() {qDebug() << "BenzModel : enginBoom";} }; class BMWModel:public CarModel { protected: virtual void start() {qDebug() << "BMWModel : start";} virtual void stop() {qDebug() << "BMWModel : stop";} virtual void alarm() {qDebug() << "BMWModel : alarm";} virtual void enginBoom() {qDebug() << "BMWModel : enginBoom";} }; class CarBuilder { public: virtual void setSequence(QList<ESequence> list) = 0; virtual CarModel* getCarModel() = 0; }; class BenzBuilder: public CarBuilder { public: BenzBuilder() {m_benz = new BenzModel();} ~BenzBuilder() {delete m_benz;} virtual void setSequence(QList<ESequence> list){this->m_benz->setSequence(list);} virtual CarModel* getCarModel() { CarModel *car = dynamic_cast<CarModel*>(m_benz); return car; } private: BenzModel *m_benz; }; class BMWBuilder: public CarBuilder { public: BMWBuilder() {m_bmw = new BMWModel();} ~BMWBuilder() {delete m_bmw;} virtual void setSequence(QList<ESequence> list){this->m_bmw->setSequence(list);} virtual CarModel* getCarModel() { CarModel *car = dynamic_cast<CarModel*>(m_bmw); return car; } private: BMWModel *m_bmw; }; int main() { //benz QList<ESequence> list; list.clear(); list.push_back(EEnginBoom); list.push_back(EAlarm); list.push_back(EStart); list.push_back(EStop); BenzBuilder benzBuilder; BenzModel *benz; benzBuilder.setSequence(list); benz = dynamic_cast<BenzModel*>(benzBuilder.getCarModel()); benz->run(); //bmw QList<ESequence> list2; list2.clear(); list2.push_back(EStop); list2.push_back(EAlarm); list2.push_back(EStart); list2.push_back(EEnginBoom); BMWBuilder bmwBuilder; BMWModel *bmw; bmwBuilder.setSequence(list2); bmw = dynamic_cast<BMWModel*>(bmwBuilder.getCarModel()); bmw->run(); return 0; }
示例三:汽車模型擴充套件,增加需求:根據不同的給定順序進行生產
1. 模板方法模式通用類圖,類圖11-3![](https://img-blog.csdn.net/2018092118231469?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0plY2tsaW5fb25saW5l/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
2. 類圖說明:
增加了一個 Director 類,負責按照指定的順序生產模型
3. 結構說明:
getABenzModel 方法:元件出A型號的賓士車模型,其過程為只有start 、stop ;沒有engineboom 、alarm 。 getBBenzModel 方法:元件出B型號的賓士車模型,其過程為 engineboom → start → stop ;沒有alarm 。 getCBMWModel 方法:元件出C型號的寶馬車模型,其過程為 alarm → start → stop ,沒有engineboom getDBMWModel 方法:元件出D型號的寶馬車模型,其過程為 start ; 沒有engineboom 、alarm 、stop
3. 模板方法模式,程式碼清單11-3:
//////// ********** 3.車輛模型擴充套件 ,程式碼清單11-3:***************//
enum ESequence
{
EStart ,
EStop ,
EAlarm ,
EEnginBoom
};
class CarModel
{
protected:
virtual void start() = 0;
virtual void stop() = 0;
virtual void alarm() = 0;
virtual void enginBoom() = 0;
public:
void setSequence(QList<ESequence> list){this->m_list = list;}
void run()
{
QList<ESequence>::const_iterator iter = this->m_list.begin();
while(iter != this->m_list.end())
{
switch (*iter)
{
case EStart:
this->start();
break;
case EStop:
this->stop();
break;
case EAlarm:
this->alarm();
break;
case EEnginBoom:
this->enginBoom();
break;
};
++iter;
}
}
private:
QList<ESequence> m_list;
};
class BenzModel:public CarModel
{
protected:
virtual void start() {qDebug() << "BenzModel : start";}
virtual void stop() {qDebug() << "BenzModel : stop";}
virtual void alarm() {qDebug() << "BenzModel : alarm";}
virtual void enginBoom() {qDebug() << "BenzModel : enginBoom";}
};
class BMWModel:public CarModel
{
protected:
virtual void start() {qDebug() << "BMWModel : start";}
virtual void stop() {qDebug() << "BMWModel : stop";}
virtual void alarm() {qDebug() << "BMWModel : alarm";}
virtual void enginBoom() {qDebug() << "BMWModel : enginBoom";}
};
class CarBuilder
{
public:
virtual void setSequence(QList<ESequence> list) = 0;
virtual CarModel* getCarModel() = 0;
};
class BenzBuilder: public CarBuilder
{
public:
BenzBuilder() {m_benz = new BenzModel();}
~BenzBuilder() {delete m_benz;}
virtual void setSequence(QList<ESequence> list){this->m_benz->setSequence(list);}
virtual CarModel* getCarModel()
{
CarModel *car = dynamic_cast<CarModel*>(m_benz);
return car;
}
private:
BenzModel *m_benz;
};
class BMWBuilder: public CarBuilder
{
public:
BMWBuilder() {m_bmw = new BMWModel();}
~BMWBuilder() {delete m_bmw;}
virtual void setSequence(QList<ESequence> list){this->m_bmw->setSequence(list);}
virtual CarModel* getCarModel()
{
CarModel *car = dynamic_cast<CarModel*>(m_bmw);
return car;
}
private:
BMWModel *m_bmw;
};
//導演類
class Director
{
public:
Director()
{
m_benzBuilder = new BenzBuilder();
m_bmwBuilder = new BMWBuilder();
}
~Director()
{
delete this->m_benzBuilder;
delete this->m_bmwBuilder;
}
BenzModel* getABenzModel()
{
this->m_list.clear();
this->m_list.push_back(EStart);
this->m_list.push_back(EStop);
this->m_benzBuilder->setSequence(this->m_list);
BenzModel *model = dynamic_cast<BenzModel*>(m_benzBuilder->getCarModel());
return model;
}
BenzModel* getBBenzModel()
{
this->m_list.clear();
this->m_list.push_back(EEnginBoom);
this->m_list.push_back(EStart);
this->m_list.push_back(EStop);
this->m_benzBuilder->setSequence(this->m_list);
BenzModel *model = dynamic_cast<BenzModel*>(m_benzBuilder->getCarModel());
return model;
}
BMWModel* getCBMWModel()
{
this->m_list.clear();
this->m_list.push_back(EAlarm);
this->m_list.push_back(EStart);
this->m_list.push_back(EStop);
this->m_bmwBuilder->setSequence(this->m_list);
BMWModel *model = dynamic_cast<BMWModel*>(m_bmwBuilder->getCarModel());
return model;
}
BMWModel* getDBMWModel()
{
this->m_list.clear();
this->m_list.push_back(EStart);
this->m_bmwBuilder->setSequence(this->m_list);
BMWModel *model = dynamic_cast<BMWModel*>(m_bmwBuilder->getCarModel());
return model;
}
private:
QList<ESequence> m_list;
BenzBuilder *m_benzBuilder;
BMWBuilder *m_bmwBuilder;
};
int main()
{
Director director;
//生產2輛A型別賓士車
for (int i = 0; i < 2; ++i){director.getABenzModel()->run();}
//3輛B型別賓士車
for (int i = 0; i < 3; ++i){director.getBBenzModel()->run();}
//4輛C型別寶馬車
for (int i = 0; i < 4; ++i){director.getCBMWModel()->run();}
return 0;
}
示例四:建造者模式的通用版本
1. 建造者模式的通用版本,類圖11-4![](https://img-blog.csdn.net/2018092118250612?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0plY2tsaW5fb25saW5l/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
2. 類圖說明:
在建造者模式中,有如下4個角色: Product 產品類: 通常是實現了模板方法模式,也就是有模板方法和基本方法。例子中的 BenzModel 和 BMWModel就屬於產品類。 Builder 抽象建造者:規範產品的元件,一般是由子類實現。例子中的CarBuilder 就屬於抽象建造者。 ConcreteBuilder 具體建造者:實現抽象類定義的所有方法,並且翻譯一個組建好的物件。例子中的 BenzBuilder 和 BMWBuilder 就屬於具體建造者。 Director 導演類:負責安排已有模組的順序,然後告訴Builder開始建造。
3. 建造者模式的通用版本,程式碼清單11-4:
////////// ********** 4.建造者模式的通用版本 ,程式碼清單11-4:***************//
class Product
{
public:
void doSomething(){qDebug() << "***";}
};
class Builder
{
public:
virtual void setPart() = 0;
virtual Product* buildProduct() = 0;
};
class ConcreteProduct: public Builder
{
public:
ConcreteProduct() {this->m_product = new Product();}
~ConcreteProduct(){delete this->m_product;}
void setPart(){} //產品類內的邏輯處理
Product* buildProduct()
{
return this->m_product;
}
private:
Product* m_product;
};
class Director
{
public:
Director() {this->m_builder = new ConcreteProduct();}
~Director(){delete this->m_builder;}
Product* getAProduct()
{
this->m_builder->setPart();
Product* product = dynamic_cast<Product*>(this->m_builder->buildProduct());
return product;
}
private:
ConcreteProduct *m_builder;
};
int main ()
{
Director director;
director.getAProduct()->doSomething();
return 0;
}
三、建造者模式的應用
1. 優點:
- 封裝性。使用建造者模式可以使客戶端不必知道產品內部組成的細節,如例子中我們不關心每一個具體模型的內部是怎樣實現的,產生的物件型別就是CarModel。
- 建造者獨立,容易擴充套件。BenzBuilder 和 BMWBuilder 是相互獨立的,對系統的擴充套件非常有利。
- 便於控制細節風險。由於具體的建造者是獨立的,因此可以對建造過程逐步細化,而不對其他模組產生任何影響。
2. 使用場景:
- 相同的方法,不同的執行順序,產生不同的時間結果時。
- 多個部件或零件,都可以裝配到一個物件中,但是產生的執行結果又不相同時。
- 產品類非常複雜,或者產品類中的呼叫順序不同產生了不同的效能。
- 在物件建立過程中會使用到系統中的一些其他物件,這些物件在產品物件的建立過程中不易得到時。該場景只是一個補償方法,因為一個物件不容易獲得,而在設計階段竟然沒有發覺。
3. 注意事項:
建造者模式關注的是零件型別和裝配工藝(順序),這是它與工廠方法模式最大的不同。
參考文獻《秦小波. 設計模式之禪》(第2版) (華章原創精品) . 機械工業出版社