大話設計模式8—建造者模式(建造小人)
- 1.需求:建造小人
- 2.普通實作
- 3.建造者模式實作
- 4.建造者模式
1.需求:建造小人
假設需要使用畫筆和圖檔畫兩個小人,小人隻需要包含頭部、身體和腿就可以。這兩個小人一個是瘦人、一個是胖子。現給出畫筆和圖檔兩個類如下:
class Pen {
public:
Pen();
};
class Graphics {
public:
Graphics();
};
構造函數
Pen::Pen() {
cout << "use yellow pen" << endl;
}
Graphics::Graphics() {
cout << "start to write" << endl;
}
main函數
int main()
{
Pen *p = new Pen();
Graphics *g = new Graphics();
//自己添加
return 0;
}
請設計BuildThinPerson和BuildFatPerson兩個類完成最終需要輸出如下。
2.普通實作
設計兩個類BuildThinPerson 和BuildFatPerson,這兩個類十分相似,都有兩個成員變量m_pen和m_graphics指針,來自題設給定的Pen和Graphics 兩個類,BuildThinPerson的方法就是畫頭、身子、腿如下。
class BuildThinPerson {
public:
BuildThinPerson(Pen *pen, Graphics *graphics);
void BuildHead();
void BuildBody();
void BuildLeg();
void BuildThin();
private:
Pen *m_pen;
Graphics *m_graphics;
};
BuildThinPerson 類的實作很簡單,由于main函數已經實作了一部分,是以BuildThinPerson 類的構造函數傳參即可。在BuildHead(); BuildBody();BuildLeg()三個函數中列印需要的輸出,而BuildThin()函數負責調用三個函數封裝起來。
BuildThinPerson::BuildThinPerson(Pen * pen, Graphics * graphics) :m_pen(pen), m_graphics(graphics) {
}
void BuildThinPerson::BuildHead() {
cout << "build Head of thin person" << endl;
}
void BuildThinPerson::BuildBody() {
cout << "build Body of thin person" << endl;
}
void BuildThinPerson::BuildLeg() {
cout << "build Leg of thin person" << endl;
}
void BuildThinPerson::BuildThin()
{
BuildHead();
BuildBody();
BuildLeg();
}
BuildFatPerson類的實作隻有列印語句和BuildThinPerson不同略去實作。那麼補全的main函數如下
int main()
{
Pen *p = new Pen();
Graphics *g = new Graphics();
BuildThinPerson *thin_person = new BuildThinPerson(p, g);
thin_person->BuildThin();
BuildFatPerson *fat_person = new BuildFatPerson(p, g);
fat_person->BuildFat();
return 0;
}
達到建造兩個小人的要求
3.建造者模式實作
檢視上述代碼,可以發現兩個類BuildThinPerson 和BuildFatPerson相似度很高,是以第一步,我們考慮把共同的東西放到新設計的父類PersonBuilder中,BuildThinPerson 和BuildFatPerson繼承他,三類如下:
class PersonBuilder {
protected:
Pen *m_pen;
Graphics *m_graphics;
public:
PersonBuilder(Pen *pen,Graphics *graphics);
virtual ~PersonBuilder() {};
virtual void BuildHead() {};
virtual void BuildBody() {};
virtual void BuildLeg() {};
};
class BuildThinPerson:public PersonBuilder{
public:
BuildThinPerson(Pen *pen, Graphics *graphics);
virtual void BuildHead();
virtual void BuildBody();
virtual void BuildLeg();
};
class BuildFatPerson:public PersonBuilder {
public:
BuildFatPerson(Pen *pen, Graphics *graphics);
virtual void BuildHead();
virtual void BuildBody();
virtual void BuildLeg();
};
這三個類實作也很簡單,子類重寫父類的BuildHead(); BuildBody();BuildLeg()函數。
PersonBuilder::PersonBuilder(Pen* pen, Graphics* graphics) : m_pen(pen), m_graphics(graphics) {
}
BuildThinPerson::BuildThinPerson(Pen* pen, Graphics* graphics): PersonBuilder(pen,graphics){
}
void BuildThinPerson::BuildHead() {
cout << "build Head of thin person" << endl;
}
void BuildThinPerson::BuildBody() {
cout << "build Body of thin person" << endl;
}
void BuildThinPerson::BuildLeg() {
cout << "build Leg of thin person" << endl;
}
BuildFatPerson::BuildFatPerson(Pen * pen, Graphics * graphics) :PersonBuilder(pen, graphics){
}
void BuildFatPerson::BuildHead() {
cout << "build Head of fat person" << endl;
}
void BuildFatPerson::BuildBody() {
cout << "build Body of fat person" << endl;
}
void BuildFatPerson::BuildLeg() {
cout << "build Leg of fat person" << endl;
}
重點來了,用戶端調用時還是需要知道建造頭、身子、腿的方法,我們想要隔絕使用者和建造過程的關聯,不讓使用者知道建造的過程和細節。是以我們還需要一個指揮者的類來控制建造過程。
指揮者PersonDirector 類管理抽象建造者類的指針,通過調用CreatPerson進行建造。
class PersonDirector {
private:
PersonBuilder* m_person_builder;
public:
PersonDirector(PersonBuilder* person_builder);
void CreatPerson();
};
PersonDirector類實作,構造函數通過使用者告訴指揮者需要建造什麼小人,而CreatPerson調用建造過程就行
PersonDirector::PersonDirector(PersonBuilder * person_builder):m_person_builder(person_builder){
}
void PersonDirector::CreatPerson()
{
m_person_builder->BuildHead();
m_person_builder->BuildBody();
m_person_builder->BuildLeg();
}
以上完成了所有類的實作,各類之間關系如下
main函數就很好寫出來了,隻需要向指揮者傳入想建立的小人就行
int main()
{
Pen *p = new Pen;
Graphics *g = new Graphics;
PersonBuilder *build1 = new BuildThinPerson(p,g);
PersonDirector *dir = new PersonDirector(build1);
dir->CreatPerson();
PersonBuilder *build2 = new BuildFatPerson(p, g);
dir = new PersonDirector(build2);
dir->CreatPerson();
delete p;
delete g;
delete build1;
delete dir;
return 0;
}
完成題設要求
所有代碼如下:
build.h
#ifndef BUILD_H
#define BUILD_H
class Pen {
public:
Pen();
};
class Graphics {
public:
Graphics();
};
class PersonBuilder {
protected:
Pen *m_pen;
Graphics *m_graphics;
public:
PersonBuilder(Pen *pen,Graphics *graphics);
virtual ~PersonBuilder() {};
virtual void BuildHead() {};
virtual void BuildBody() {};
virtual void BuildLeg() {};
};
class BuildThinPerson:public PersonBuilder{
public:
BuildThinPerson(Pen *pen, Graphics *graphics);
virtual void BuildHead();
virtual void BuildBody();
virtual void BuildLeg();
};
class BuildFatPerson:public PersonBuilder {
public:
BuildFatPerson(Pen *pen, Graphics *graphics);
virtual void BuildHead();
virtual void BuildBody();
virtual void BuildLeg();
};
class PersonDirector {
private:
PersonBuilder* m_person_builder;
public:
PersonDirector(PersonBuilder* person_builder);
void CreatPerson();
};
#endif
build.cpp
#include"build.h"
#include<iostream>
using namespace std;
Pen::Pen(){
cout << "use yellow pen" << endl;
}
Graphics::Graphics(){
cout << "start to write" << endl;
}
PersonBuilder::PersonBuilder(Pen* pen, Graphics* graphics) : m_pen(pen), m_graphics(graphics) {
}
BuildThinPerson::BuildThinPerson(Pen* pen, Graphics* graphics): PersonBuilder(pen,graphics){
}
void BuildThinPerson::BuildHead() {
cout << "build Head of thin person" << endl;
}
void BuildThinPerson::BuildBody() {
cout << "build Body of thin person" << endl;
}
void BuildThinPerson::BuildLeg() {
cout << "build Leg of thin person" << endl;
}
BuildFatPerson::BuildFatPerson(Pen * pen, Graphics * graphics) :PersonBuilder(pen, graphics){
}
void BuildFatPerson::BuildHead() {
cout << "build Head of fat person" << endl;
}
void BuildFatPerson::BuildBody() {
cout << "build Body of fat person" << endl;
}
void BuildFatPerson::BuildLeg() {
cout << "build Leg of fat person" << endl;
}
PersonDirector::PersonDirector(PersonBuilder * person_builder):m_person_builder(person_builder){
}
void PersonDirector::CreatPerson()
{
m_person_builder->BuildHead();
m_person_builder->BuildBody();
m_person_builder->BuildLeg();
}
main.cpp
#include"build.h"
int main()
{
Pen *p = new Pen;
Graphics *g = new Graphics;
PersonBuilder *build1 = new BuildThinPerson(p,g);
PersonDirector *dir = new PersonDirector(build1);
dir->CreatPerson();
PersonBuilder *build2 = new BuildFatPerson(p, g);
dir = new PersonDirector(build2);
dir->CreatPerson();
delete p;
delete g;
delete build1;
delete dir;
return 0;
}
4.建造者模式
建造者模式:将一個複雜對象的建構與它的表示分離,使得同樣的建構過程可以建立不同的表示。使用者隻需要指定需要建造的類型就可以的得到他們,而具體的建構過程和細節不需要知道。
如下圖所示,Builder是建立小人的抽象類,具體建造者繼承他進行構造和裝配。
建造者模式主要用于建立一些複雜對象,這些對象内部構造間的順序通常是穩定的,但對象内部的構造通常面臨複雜變化。