文章目錄
思考:
為何肯德基麥當勞這些快餐能在中國這個上下五千年的國都站住腳? 中國的魚香肉絲為何不能成為令人追捧的快餐?
因為麥當勞肯德基使用的是統一制造的快餐, 也就相當于廚師是一個廚師, 而中國的飯店每個都有魚香肉絲, 但是中國的飯店每個店的廚師都不相同, 魚香肉絲的味道也各不相同, 正是因為這樣的差別, 我們不確定未吃過的店里面的魚香肉絲是否使我們想吃的, 而肯德基我們不管在哪家店, 吃的漢堡都是一個味道的, 只要喜歡吃, 任意哪家的都可以吃;
因此魚香肉絲依賴于廚師, 想想設計模式的原則?
依賴倒轉原則: 抽象不應該依賴細節, 但是細節應該依賴抽象, 這樣做的結果就是很被動; 而肯德基可以的工作流程相當于抽象流程(放料,燒烤,摸辣等), 具體放什么配料, 烤多長時間等細節都是依賴于這個抽象;
本文還涉及到兩個知識點
- delete
在本文之前,我的delete都是使用的delete p1, p2, p3這樣的格式, 但是這樣做是錯誤的, 因為上面的語句表達的是: delete p1; p2; p3, 因此只刪除了p1; 此外在C++中, 由于編譯器不負責delete p1這樣的指針, 因此當delete執行完畢后, 只回收了p1指向的堆內存空間, 但是p1這個指針依然真實存在的, 此時p1已經成為了野指針, 因此delete p1后, 還需要把p1刪除, 刪除的格式是 p1 = nullptr, 這樣后面就無法在訪問這個p1的指針了 - 析構函數
當子類繼承基類, 子類中會生成指針對象, 并且要在子類析構時回收這個對象, 那么必須要在基類的析構函數定義為虛函數, 這樣一旦有多態的情況就可以對子類里面的指針對象進行回收了.
class A
{
public
: virtual
~A(){} virtual
void getName(){};
};class B
: public A
{
private
:string name
;
public
:A
* a
= new
A();B(string n
): name(n
){}~B(){ delete a
; a
= nullptr
;cout
<< "析構" << name
<<endl
;}void getName(){cout
<< "name = "<< name
<<endl
;}
};int main(int argc
, char const *argv
[])
{A
* b1
= new
B("b1");A
* b2
= new
B("b2");A
* b3
= new
B("b3");A
* b4
= new
B("b4");delete b1
,b2
,b3
,b4
;b1
= nullptr
;if(b1
){cout
<< "b1 不空, 可以使用" <<endl
;b1
->getName();}cout
<< "這里才是正經的刪除不同的指針對象" <<endl
;delete b2
, delete b3
, delete b4
; b2
=b3
=b4
=nullptr
;return 0;
}
1. 理論基礎
目的:
將一個復雜的構建與其表示相分離,使得同樣的構建過程可以創建不同的表示。
主要解決:
主要解決在軟件系統中,有時候面臨著"一個復雜對象"的創建工作,其通常由各個部分的子對象用一定的算法構成;由于需求的變化,這個復雜對象的各個部分經常面臨著劇烈的變化,但是將它們組合在一起的算法卻相對穩定。
何時使用:
一些基本部件不會變,而其組合經常變化的時候。
如何解決:
將變與不變分離開。
關鍵代碼:
建造者:創建和提供實例,
導演:管理建造出來的實例的依賴關系。
應用實例:
1、去肯德基,漢堡、可樂、薯條、炸雞翅等是不變的,而其組合是經常變化的,生成出所謂的"套餐"。
2、JAVA 中的 StringBuilder。
優點:
1、建造者獨立,易擴展。 2、便于控制細節風險。
缺點:
1、產品必須有共同點,范圍有限制。 2、如內部變化復雜,會有很多的建造類。
使用場景:
1、需要生成的對象具有復雜的內部結構。 2、需要生成的對象內部屬性本身相互依賴。
注意事項:
與工廠模式的區別是:建造者模式更加關注與零件裝配的順序。
2. 邏輯代碼
如上圖所示:
- Builder相當于制作漢堡的抽象類, 為Product對象的各個部件指定的抽象接口
- ConcreteBuilder相當于具體實現制作漢堡的各個細節流程
- Director指揮者, 根據用戶需要構建不同的漢堡
- 什么時候需要使用到建造者模式呢? 用于創建一些復雜對象, 這些對象內部構建間的構造順序通常是穩定的, 但對象內部的構建通常面臨著復雜的變化
#include <iostream>
#include <algorithm>
#include <string.h>
#include <list>
using namespace std
;
class Product
{
private
:list
<string
> parts
;
public
:virtual
~Product(){}void Add(string part
){parts
.push_back(part
);}void Show(){cout
<< "產品創建 ... " <<endl
;for(auto &s
: parts
){cout
<< s
<<endl
;}}
};
class Builder
{
public
:virtual
~Builder(){}virtual
void BuildPartA() = 0;virtual
void BuildPartB() = 0;virtual Product
*GetResult() = 0;
};
class ConcreteBuilder1
: public Builder
{
private
:Product
*product
= new
Product();
public
:~ConcreteBuilder1(){cout
<< "jjjj" <<endl
;try
{delete product
; product
= nullptr
;}catch(const std
::exception
& e
) {std
::cerr
<< e
.what() << '\n';}}void BuildPartA(){product
->Add("部件 A");}void BuildPartB(){product
->Add("部件 B");}Product
* GetResult(){return product
;}
};
class ConcreteBuilder2
: public Builder
{
private
:Product
*product
= new
Product();
public
:~ConcreteBuilder2(){cout
<< "刪除成功?? " <<endl
;delete product
; product
= nullptr
;}void BuildPartA(){product
->Add("部件 X");}void BuildPartB(){product
->Add("部件 Y");}Product
* GetResult(){return product
;}
};
class Director
{
public
:~Director(){cout
<< "delete Direct" <<endl
;}void Construct(Builder
*builder
){builder
->BuildPartA();builder
->BuildPartB();}
};int main(int argc
, char const *argv
[])
{Builder
*b1
= new
ConcreteBuilder1();Builder
*b2
= new
ConcreteBuilder2();Director
*director
= new
Director();director
->Construct(b1
);Product
*p1
= b1
->GetResult();p1
->Show();director
->Construct(b2
);Product
*p2
= b2
->GetResult();p2
->Show();delete b1
; b1
= nullptr
;delete b2
; b2
= nullptr
;delete director
; director
= nullptr
;return 0;
}
3. 應用
3.1 做漢堡咯
三層
產品
建造者
指揮者
客戶
class Product
{
private
:list
<string
> parts
;
public
:virtual
~Product(){}void Add(string part
){parts
.push_back(part
);}void Show(){cout
<< "產品創建 ... " <<endl
;for(auto &s
: parts
){cout
<< s
<<endl
;}}
};
class Builder
{
public
:virtual
~Builder(){}virtual
void BuildPartA() = 0;virtual
void BuildPartB() = 0;virtual
void BuildPartC() = 0;virtual Product
*GetResult() = 0;
};
class ConcreteBuilderSJ
: public Builder
{
private
:Product
*product
= new
Product();
public
:~ConcreteBuilder1(){delete product
; product
= nullptr
;}void BuildPartA(){product
->Add("油炸10小時");}void BuildPartB(){product
->Add("咸鹽20斤");}void BuildPartC(){product
->Add("芥末1kg");}Product
* GetResult(){return product
;}
};
class ConcreteBuilderJMJ
: public Builder
{
private
:Product
*product
= new
Product();
public
:~ConcreteBuilder2(){cout
<< "刪除成功?? " <<endl
;delete product
; product
= nullptr
;}void BuildPartA(){product
->Add("油炸1小時");}void BuildPartB(){product
->Add("咸鹽2斤");}void BuildPartC(){product
->Add("芥末100噸");}Product
* GetResult(){return product
;}
};
class Director
{
public
:~Director(){cout
<< "delete Direct" <<endl
;}void Construct(Builder
*builder
){builder
->BuildPartA();builder
->BuildPartB();builder
->BuildPartC();}
};int main(int argc
, char const *argv
[])
{Builder
*b1
= new
ConcreteBuilderSJ(); Builder
*b2
= new
ConcreteBuilderJMJ(); Director
*director
= new
Director(); director
->Construct(b1
); Product
*p1
= b1
->GetResult();p1
->Show(); director
->Construct(b2
);Product
*p2
= b2
->GetResult();p2
->Show();delete b1
; b1
= nullptr
;delete b2
; b2
= nullptr
;delete director
; director
= nullptr
;return 0;
}
總結
以上是生活随笔為你收集整理的C++ 设计模式 建造者模式(复杂对象的构建与其表示分离)肯德基不同烧鸡的制作过程的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。