設計模式4 結構型模式
目錄 代理模式 裝飾器 外觀模式 適配器模式
代理模式,美國,韓國代理購物
chunli@linux:~$ cat main.cpp
#include<iostream>
using namespace std;
class Item //商品
{
public:
Item(string kind ,bool fact)
{
this->kind = kind;
this->fact = fact;
}
string getKind()
{
return kind;
}
bool getFact()
{
return fact;
}
private:
string kind ;
bool fact;
};
class Shopping //抽象的購物方式
{
public:
virtual void buy(Item *it) =0;
};
class KoreaShopping:public Shopping //Korea購物
{
public:
virtual void buy(Item *it)
{
cout << "去Korea 買了" << it->getKind() << endl;
}
};
class USAShopping:public Shopping //USA購物
{
public:
virtual void buy(Item *it)
{
cout << "去USA 買了" << it->getKind() << endl;
}
};
int main()
{
Item it_1("Nike鞋",true);
if(it_1.getFact() == true) //辨別產品真假
{
cout << "發現真貨" << endl;
Shopping *koreaShopping = new KoreaShopping;
koreaShopping->buy(&it_1);//代理
cout << "過安檢" << endl;
}
else
{
cout << "假貨,不要買" << endl;
}
Item it_2("英語證書",false);
return 0;
}
chunli@linux:~$ g++ main.cpp -Wall && ./a.out
發現真貨
去Korea 買了Nike鞋
過安檢
chunli@linux:~$代理模式,海外代理韓國與美國
chunli@linux:~$ cat main.cpp
#include<iostream>
using namespace std;
class Item //商品
{
public:
Item(string kind ,bool fact)
{
this->kind = kind;
this->fact = fact;
}
string getKind()
{
return kind;
}
bool getFact()
{
return fact;
}
private:
string kind ;
bool fact;
};
class Shopping //抽象的購物方式
{
public:
virtual void buy(Item *it) =0;
};
class KoreaShopping:public Shopping //Korea購物
{
public:
virtual void buy(Item *it)
{
cout << "去Korea 買了" << it->getKind() << endl;
}
};
class USAShopping:public Shopping //USA購物
{
public:
virtual void buy(Item *it)
{
cout << "去USA 買了" << it->getKind() << endl;
}
};
class OverseaProxy:public Shopping
{
public:
OverseaProxy(Shopping *shopping)
{
this->shopping = shopping;
}
virtual void buy(Item *it)
{
//購買之前............
if(it->getFact() == false)
{
cout << "發現假貨,不要購買" << endl;
return ;
}
//開始購買
shopping->buy(it);
//購買之后
cout << "通過安檢,后買成功!" << endl;
}
private:
Shopping *shopping;
};
int main()
{
Shopping *usaShopping = new USAShopping;
Shopping *overseaProxy = new OverseaProxy(usaShopping);
Item it1("英語證書",false); overseaProxy->buy(&it1);
Item it2("Dell 服務器",true); overseaProxy->buy(&it2);
return 0;
}
chunli@linux:~$ g++ main.cpp -Wall && ./a.out
發現假貨,不要購買
去USA 買了Dell 服務器
通過安檢,后買成功!
chunli@linux:~$看圖:


subject(抽象主題角色):真實主題與代理主題的共同接口。
RealSubject(真實主題角色):定義了代理角色所代表的真實對象。
Proxy(代理主題角色): 含有對真實主題角色的引用,代理角色通常在
將客戶端調用傳遞給真是主題對象之前或者之后執行某些操作,而不是單純返
回真實的對象。
優點:
(1) 能夠協調調用者和被調用者,在一定程度上降低了系統的耦合度。
(2) 客戶端可以針對抽象主題角色進行編程,增加和更換代理類無須修改源
代碼,符合開閉原則,系統具有較好的靈活性和可擴展性。
缺點:
(1) 代理實現較為復雜。
---------------------------------------------------------------------
裝飾器:把手機裸機 裝飾成有貼膜的手機
chunli@linux:~$ cat main.cpp
#include<iostream>
using namespace std;
class Phone
{
public:
virtual void show() = 0;
};
class iPhone:public Phone
{
public:
virtual void show()
{
cout << "秀出了iPhone"<< endl;
}
};
class Mi:public Phone
{
public:
virtual void show()
{
cout << "秀出了 小米"<< endl;
}
};
//抽象裝飾器
class Decorator:public Phone
{
public:
Decorator(Phone *phone)
{
this->phone = phone;
}
virtual void show() = 0;
protected:
Phone *phone;//擁有一個手機的父類指針
};
//貼膜裝飾器
class MoDecorator:public Decorator
{
public:
MoDecorator(Phone *phone):Decorator(phone)
{
}
virtual void show()
{
this->phone->show();
this->mo();
}
void mo()
{
cout << "手機 貼膜了 " << endl;
}
};
int main()
{
Phone *phone = new iPhone; //創建一個裸機
phone->show();//裸機 show()
cout << "---------------" <<endl;
Phone *mophone = new MoDecorator(phone);
mophone->show();
return 0;
}
chunli@linux:~$ g++ main.cpp -Wall && ./a.out
秀出了iPhone
---------------
秀出了iPhone
手機 貼膜了
chunli@linux:~$裝飾器,在貼膜的手機,加殼
chunli@linux:~$ g++ main.cpp -Wall && ./a.out
秀出了iPhone
---------------
秀出了iPhone
手機 貼膜了
---------------
秀出了iPhone
手機 貼膜了
手機 加殼了
chunli@linux:~$
chunli@linux:~$ cat main.cpp
#include<iostream>
using namespace std;
class Phone
{
public:
virtual void show() = 0;
};
class iPhone:public Phone
{
public:
virtual void show()
{
cout << "秀出了iPhone"<< endl;
}
};
class Mi:public Phone
{
public:
virtual void show()
{
cout << "秀出了 小米"<< endl;
}
};
//抽象裝飾器
class Decorator:public Phone
{
public:
Decorator(Phone *phone)
{
this->phone = phone;
}
virtual void show() = 0;
protected:
Phone *phone;//擁有一個手機的父類指針
};
//貼膜裝飾器
class MoDecorator:public Decorator
{
public:
MoDecorator(Phone *phone):Decorator(phone)
{
}
virtual void show()
{
this->phone->show();
this->mo();
}
void mo()
{
cout << "手機 貼膜了 " << endl;
}
};
//手機殼 裝飾器
class ShellDecorator:public Decorator
{
public:
ShellDecorator(Phone *phone):Decorator(phone)
{
}
virtual void show()
{
this->phone->show();
this->shell();
}
void shell()
{
cout << "手機 加殼了 " << endl;
}
};
int main()
{
Phone *phone = new iPhone; //創建一個裸機
phone->show();//裸機 show()
cout << "---------------" <<endl;
Phone *mophone = new MoDecorator(phone);
mophone->show();
cout << "---------------" <<endl;
Phone *shellPhone = new ShellDecorator(mophone);
shellPhone->show();
return 0;
}
chunli@linux:~$ g++ main.cpp -Wall && ./a.out
秀出了iPhone
---------------
秀出了iPhone
手機 貼膜了
---------------
秀出了iPhone
手機 貼膜了
手機 加殼了
chunli@linux:~$看圖

Component(抽象構件): 它是具體構件和抽象裝飾類的共同父類,聲
明了在具體構件中實現的業務方法,它的引入可以使客戶端以一致的方式處理
未被裝飾的對象以及裝飾之后的對象,實現客戶端的透明操作。
ConcreteComponent(具體構件): 它是抽象構件類的子類,用于定
義具體的構件對象,實現了在抽象構件中聲明的方法,裝飾器可以給它增加額
外的職責(方法)。
Decorator(抽象裝飾類): 它也是抽象構件類的子類,用于給具體構件
增加職責,但是具體職責在其子類中實現。它維護一個指向抽象構件對象的引
用,通過該引用可以調用裝飾之前構件對象的方法,并通過其子類擴展該方法,
以達到裝飾的目的。
ConcreteDecorator(具體裝飾類):它是抽象裝飾類的子類,負責向
構件添加新的職責。每一個具體裝飾類都定義了一些新的行為,它可以調用在
抽象裝飾類中定義的方法,并可以增加新的方法用以擴充對象的行為。
4.2.3 裝飾模式的優缺點
優點:
(1) 對于擴展一個對象的功能,裝飾模式比繼承更加靈活性,不會導致類的個數
急劇增加。
(2) 可以通過一種動態的方式來擴展一個對象的功能,從而實現不同的行為。
(3) 可以對一個對象進行多次裝飾。
(4) 具體構件類與具體裝飾類可以獨立變化,用戶可以根據需要增加新的具體構
件類和具體裝飾類,原有類庫代碼無須改變,符合“開閉原則”。
缺點:
(1) 使用裝飾模式進行系統設計時將產生很多小對象,大量小對象的產生勢必會
占用更多的系統資源,影響程序的性能。
外觀模式: 演示:為了調用AB方法,需要顯式的調用AB
chunli@linux:~$ cat main.cpp
#include<iostream>
using namespace std;
class SysA
{
public:
void operationA()
{
cout << "A........" << endl;
}
};
class SysB
{
public:
void operationB()
{
cout << "B........" << endl;
}
};
class SysC
{
public:
void operationC()
{
cout << "C........" << endl;
}
};
class SysD
{
public:
void operationD()
{
cout << "D........" << endl;
}
};
int main()
{
SysA sysa; sysa.operationA();
SysB sysb; sysb.operationB();
return 0;
}
chunli@linux:~$ g++ main.cpp && ./a.out
A........
B........
chunli@linux:~$現在只需要通過外觀訪問:打包組合起來
chunli@linux:~$ cat main.cpp
#include<iostream>
using namespace std;
class SysA
{
public:
void operationA()
{
cout << "A........" << endl;
}
};
class SysB
{
public:
void operationB()
{
cout << "B........" << endl;
}
};
class SysC
{
public:
void operationC()
{
cout << "C........" << endl;
}
};
class SysD
{
public:
void operationD()
{
cout << "D........" << endl;
}
};
class Facade
{
public:
void methodOne()
{
sysa.operationA();
sysb.operationB();
}
void methodTwo()
{
sysc.operationC();
sysd.operationD();
}
private:
SysA sysa;
SysB sysb;
SysC sysc;
SysD sysd;
};
int main()
{
Facade face; face.methodOne();
return 0;
}
chunli@linux:~$ g++ main.cpp && ./a.out
A........
B........
chunli@linux:~$適配器模式
手機充電需要使用5V電壓,
創建一個適配器,將220V電壓轉換成5V
chunli@linux:~$ cat main.cpp
#include <iostream>
using namespace std;
class V5
{
public:
virtual void useV5() = 0;
};
//目前只有v220的類 沒有v5
class V220
{
public:
void useV220()
{
cout << "使用了220v的電壓" << endl;
}
};
//定義一個中間的適配器類
class Adapter :public V5
{
public:
Adapter(V220 * v220)
{
this->v220 = v220;
}
~Adapter() {
if (this->v220 != NULL)
{
delete this->v220;
}
}
virtual void useV5()
{
v220->useV220(); //調用需要另外的方法
}
private:
V220 *v220;
};
class iPhone
{
public:
iPhone(V5 *v5)
{
this->v5 = v5;
}
~iPhone()
{
if (this->v5 != NULL) {
delete this->v5;
}
}
//充電的方法
void charge()
{
cout << "iphone手機進行了充電" << endl;
v5->useV5();
}
private:
V5*v5;
};
int main(void)
{
iPhone *phone = new iPhone(new Adapter(new V220));
phone->charge();
return 0;
}
chunli@linux:~$ g++ main.cpp && ./a.out
iphone手機進行了充電
使用了220v的電壓
chunli@linux:~$適配器模式中的角色和職責

Target(目標抽象類): 目標抽象類定義客戶所需接口,可以是一個抽
象類或接口,也可以是具體類。
Adapter(適配器類):適配器可以調用另一個接口,作為一個轉換
器,對Adaptee和Target進行適配,適配器類是適配器模式的核心,在對象適
配器中,它通過繼承Target并關聯一個Adaptee對象使二者產生聯系。
Adaptee(適配者類):適配者即被適配的角色,它定義了一個已經存在
的接口,這個接口需要適配,適配者類一般是一個具體類,包含了客戶希望使
用的業務方法,在某些情況下可能沒有適配者類的源代碼。
根據對象適配器模式結構圖,在對象適配器中,客戶端需要調用request(
方法,而適配者類Adaptee沒有該方法,但是它所提供的specificRequest()方
法卻是客戶端所需要的。為了使客戶端能夠使用適配者類,需要提供一個包裝
類Adapter,即適配器類。這個包裝類包裝了一個適配者的實例,從而將客戶
端與適配者銜接起來,在適配器的request()方法中調用適配者的
specificRequest()方法。因為適配器類與適配者類是關聯關系(也可稱之為委
派關系),所以這種適配器模式稱為對象適配器模式。
4.4.3 適配器模式優缺點
優點:
(1) 將目標類和適配者類解耦,通過引入一個適配器類來重用現有的適配者
類,無須修改原有結構。
(2) 增加了類的透明性和復用性, 將具體的業務實現過程封裝在適配者類
中,對于客戶端類而言是透明的,而且提高了適配者的復用性,同一個適配者
類可以在多個不同的系統中復用。
(3) 靈活性和擴展性都非常好 ,可以很方便地更換適配器,也可以在不修改
原有代碼的基礎上增加新的適配器類,完全符合“開閉原則”。
缺點:
適配器中置換適配者類的某些方法比較麻煩。
適應場景
(1) 系統需要使用一些現有的類,而這些類的接口(如方法名)不符合系
統的需要,甚至沒有這些類的源代碼。
(2) 想創建一個可以重復使用的類,用于與一些彼此之間沒有太大關聯的
一些類,包括一些可能在將來引進的類一起工作。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。