敏捷软件开发学习笔记(四)之结构型设计模式
PHP結(jié)構(gòu)型設(shè)計(jì)模式
參考
- 設(shè)計(jì)模式
- PHP 設(shè)計(jì)模式全集 2018
什么是結(jié)構(gòu)型是設(shè)計(jì)模式
結(jié)構(gòu)型模式講的是如何將類和對象按照某種布局組成更大的結(jié)構(gòu)。它分為類結(jié)構(gòu)型模式和對象結(jié)構(gòu)型模式,其中類結(jié)構(gòu)型模式采用繼承機(jī)制來組織接口和類,其中對象結(jié)構(gòu)型模式采用組合和聚合來組合對象。由于組合和聚合比繼承的耦合性低,滿足“合成復(fù)用原則”,所以對象結(jié)構(gòu)型模式比類結(jié)構(gòu)型模式具有更大的靈活性。
1.適配器設(shè)計(jì)模式(Adapter模式)
在現(xiàn)實(shí)生活中有很多類似的例子,如用直流電的筆記本電腦接交流電源時(shí)需要一個(gè)電源適配器,用計(jì)算機(jī)訪問照相機(jī)的 SD 內(nèi)存卡時(shí)需要一個(gè)讀卡器等。
為什么需要適配器設(shè)計(jì)模式?
在軟件設(shè)計(jì)中也可能出現(xiàn):需要開發(fā)的具有某種業(yè)務(wù)功能的組件在現(xiàn)有的組件庫中已經(jīng)存在,但它們與當(dāng)前系統(tǒng)的接口規(guī)范不兼容,如果重新開發(fā)這些組件成本又很高,這時(shí)用適配器模式能很好地解決這些問題。
什么是適配器設(shè)計(jì)模式?
適配器模式(Adapter)包含以下主要角色。
- 目標(biāo)(Target)接口:當(dāng)前系統(tǒng)業(yè)務(wù)所期待的接口,它可以是抽象類或接口。
- 適配者(Adaptee)類:它是被訪問和適配的現(xiàn)存組件庫中的組件接口。
- 適配器(Adapter)類:它是一個(gè)轉(zhuǎn)換器,通過繼承或引用適配者的對象,把適配者接口轉(zhuǎn)換成目標(biāo)接口,讓客戶按目標(biāo)接口的格式訪問適配者。
即現(xiàn)在想要在 目標(biāo)接口 中調(diào)用 適配者類 中的某些方法,所以定義一個(gè) 適配器類 繼承 適配者類,實(shí)現(xiàn)目標(biāo)接口。
分類
適配器模式分為類結(jié)構(gòu)型模式和對象結(jié)構(gòu)型模式兩種,前者類之間的耦合度比后者高,且要求程序員了解現(xiàn)有組件庫中的相關(guān)組件的內(nèi)部結(jié)構(gòu),所以應(yīng)用相對較少些。
實(shí)例
實(shí)例一:使用類結(jié)構(gòu)型模式
第一步:首先需要一個(gè)適配者類(已經(jīng)存在的)
class Adaptee{public function usedMethod(){echo "this is Adaptee method";} }第二步:現(xiàn)在想要開發(fā)一個(gè)組件(源系統(tǒng)中存在,但是不符合規(guī)范)
interface Target{public function request(); }第三步:定義一個(gè)適配器類
class Adapter extends Adaptee implements Target{public function request(){$this->usedMethod();} }第四步:使用
$adapter = new Adapter(); $adapter->request();實(shí)例二:使用對象結(jié)構(gòu)型模式
前兩個(gè)條件與上面相同
第三步:定義一個(gè)適配器類
class Adapter implements Target{public $adaptee;public function __construct(Adaptee $adaptee){$this->adaptee = $adaptee;} public function request(){$this->adaptee->usedMethod();} }第四步:使用
$adapter = new Adapter(); $adapter->request(new Adaptee());模式的應(yīng)用場景
適配器模式(Adapter)通常適用于以下場景。
- 以前開發(fā)的系統(tǒng)存在滿足新系統(tǒng)功能需求的類,但其接口同新系統(tǒng)的接口不一致。
- 使用第三方提供的組件,但組件接口定義和自己要求的接口定義不同。
2. 代理模式(Proxy)
在有些情況下,一個(gè)客戶不能或者不想直接訪問另一個(gè)對象,這時(shí)需要找一個(gè)中介幫忙完成某項(xiàng)任務(wù),這個(gè)中介就是代理對象。例如,購買火車票不一定要去火車站買,可以通過 12306 網(wǎng)站或者去火車票代售點(diǎn)買。又如找女朋友、找保姆、找工作等都可以通過找中介完成。
為什么需要代理模式?
在軟件設(shè)計(jì)中,如果由于某些原因(如安全)不想訪問真實(shí)對象的話,可以使用代理模式。
什么是代理模式?
代理模式主要分為以下幾個(gè)角色:
- 抽象主題(Subject)類:通過接口或抽象類聲明真實(shí)主題和代理對象實(shí)現(xiàn)的業(yè)務(wù)方法。
- 真實(shí)主題(Real Subject)類:實(shí)現(xiàn)了抽象主題中的具體業(yè)務(wù),是代理對象所代表的真實(shí)對象,是最終要引用的對象。
- 代理(Proxy)類:提供了與真實(shí)主題相同的接口,其內(nèi)部含有對真實(shí)主題的引用,它可以訪問、控制或擴(kuò)展真實(shí)主題的功能。
實(shí)例
第一步:首先存在一個(gè)抽象主題接口
Interface Subject{public function request(); }第二步:存在一個(gè)真實(shí)主題
class RealSubject implements Subject{public function request(){echo "這個(gè)是真實(shí)主題\n";} }第三步:使用一個(gè)代理模式
class Proxy implements Subject{public $realSubject;public function __construct(){$this->realSubject = new RealSubject(); }public function request(){$this->preRequest();$this->realSubject->request();$this->postRequest();}public function preRequest(){echo "這是調(diào)用真實(shí)主題之前的\n";}public function postRequest(){echo "這是調(diào)用真實(shí)主題之后的\n";} }第四步:測試
$testProxy = new Proxy(); $testProxy->request();d模式的應(yīng)用場景
- 遠(yuǎn)程代理,這種方式通常是為了隱藏目標(biāo)對象存在于不同地址空間的事實(shí),方便客戶端訪問。例如,用戶申請某些網(wǎng)盤空間時(shí),會(huì)在用戶的文件系統(tǒng)中建立一個(gè)虛擬的硬盤,用戶訪問虛擬硬盤時(shí)實(shí)際訪問的是網(wǎng)盤空間。
- 虛擬代理,這種方式通常用于要?jiǎng)?chuàng)建的目標(biāo)對象開銷很大時(shí)。例如,下載一幅很大的圖像需要很長時(shí)間,因某種計(jì)算比較復(fù)雜而短時(shí)間無法完成,這時(shí)可以先用小比例的虛擬代理替換真實(shí)的對象,消除用戶對服務(wù)器慢的感覺。
- 安全代理,這種方式通常用于控制不同種類客戶對真實(shí)對象的訪問權(quán)限。
- 智能指引,主要用于調(diào)用目標(biāo)對象時(shí),代理附加一些額外的處理功能。例如,增加計(jì)算真實(shí)對象的引用次數(shù)的功能,這樣當(dāng)該對象沒有被引用時(shí),就可以自動(dòng)釋放它。
- 延遲加載,指為了提高系統(tǒng)的性能,延遲對目標(biāo)的加載。例如,Hibernate 中就存在屬性的延遲加載和關(guān)聯(lián)表的延時(shí)加載。
3. 橋梁模式(Bridge)
引用設(shè)計(jì)模式(八)橋梁模式(Bridge),這篇文章中的一個(gè)例子:
現(xiàn)需要提供大中小3種型號的畫筆,能夠繪制5種不同顏色,如果使用蠟筆,我們需要準(zhǔn)備3*5=15支蠟筆,也就是說必須準(zhǔn)備15個(gè)具體的蠟筆類。而如果使用毛筆的話,只需要3種型號的毛筆,外加5個(gè)顏料盒,用3+5=8個(gè)類就可以實(shí)現(xiàn)15支蠟筆的功能。實(shí)際上,蠟筆和毛筆的關(guān)鍵一個(gè)區(qū)別就在于筆和顏色是否能夠分離。
為什么需要Bridge模式?
一個(gè)類中有多個(gè)緯度的變化,那可以使用Bridge模式對該類進(jìn)行解耦,即將多個(gè)緯度進(jìn)行抽象。所以橋梁模式的用意是“將抽象化與實(shí)現(xiàn)化脫耦,使得二者可以獨(dú)立地變化。”
什么是Bridge模式?
橋接(Bridge)模式包含以下主要角色。
- 抽象化(Abstraction)角色:定義抽象類,并包含一個(gè)對實(shí)現(xiàn)化對象的引用。
- 擴(kuò)展抽象化(Refined Abstraction)角色:是抽象化角色的子類,實(shí)現(xiàn)父類中的業(yè)務(wù)方法,并通過組合關(guān)系調(diào)用實(shí)現(xiàn)化角色中的業(yè)務(wù)方法。
- 實(shí)現(xiàn)化(Implementor)角色:定義實(shí)現(xiàn)化角色的接口,供擴(kuò)展抽象化角色調(diào)用。
- 具體實(shí)現(xiàn)化(Concrete Implementor)角色:給出實(shí)現(xiàn)化角色接口的具體實(shí)現(xiàn)。
實(shí)例
可以實(shí)現(xiàn)一個(gè)包含顏色的形狀接口。
第一步:定義一個(gè)顏色接口(Implementor角色)。定義一個(gè)形狀抽象類(Abstraction角色),其中包含一個(gè)顏色接口的引用。
//定義顏色接口 Interface Color{public function showColor(); }//形狀抽象類 abstract class Shape {protected $color;public function __construct(Color $color){$this->color = $color;}public function setColor(Color $color){$this->color = $color;}abstract public function draw(); }第二步:實(shí)現(xiàn)具體化實(shí)現(xiàn)角色(Concrete Implementor)
class Red implements Color{public function showColor(){return "red";} }class Green implements Color{public function showColor(){return "green";} }第三步:實(shí)現(xiàn)擴(kuò)展抽象化(Refined Abstraction)角色
class Square extends Shape{public function draw(){echo "i am " . $this->color->showColor() . " square\n";} }第四步:測試
$redSquare = new Square(new Red()); $redSquare->draw(); $greenSquare = new Square(new Green()); $greenSquare->draw();4.裝飾模式(Decorator)
在現(xiàn)實(shí)生活中,常常需要對現(xiàn)有產(chǎn)品增加新的功能或美化其外觀,如房子裝修、相片加相框等。
為什么需要裝飾模式?
在軟件開發(fā)過程中,有時(shí)想用一些現(xiàn)存的組件。這些組件可能只是完成了一些核心功能。但在不改變其結(jié)構(gòu)的情況下,可以動(dòng)態(tài)地?cái)U(kuò)展其功能。所有這些都可以釆用裝飾模式來實(shí)現(xiàn)。
什么是裝飾模式?
裝飾(Decorator)模式的定義:指在不改變現(xiàn)有對象結(jié)構(gòu)的情況下,動(dòng)態(tài)地給該對象增加一些職責(zé)(即增加其額外功能)的模式,它屬于對象結(jié)構(gòu)型模式。
裝飾模式主要包含以下角色。
- 抽象構(gòu)件(Component)角色:定義一個(gè)抽象接口以規(guī)范準(zhǔn)備接收附加責(zé)任的對象。
- 具體構(gòu)件(Concrete Component)角色:實(shí)現(xiàn)抽象構(gòu)件,通過裝飾角色為其添加一些職責(zé)。
- 抽象裝飾(Decorator)角色:繼承抽象構(gòu)件,并包含具體構(gòu)件的實(shí)例,可以通過其子類擴(kuò)展具體構(gòu)件的功能。
- 具體裝飾(ConcreteDecorator)角色:實(shí)現(xiàn)抽象裝飾的相關(guān)方法,并給具體構(gòu)件對象添加附加的責(zé)任。
實(shí)例
比如現(xiàn)在有一個(gè)輸出字符串接口,現(xiàn)在只能輸出原有字符串,現(xiàn)在想要增加輸出JSON,XML等字符串的功能。
第一步:先定義系統(tǒng)中已經(jīng)存在的構(gòu)件
Interface Component{public function renderData(); }class ConcreteComponent implements Component{public $data; public function __construct($data){$this->data = $data;}//輸出字符串功能public function renderData(){return $this->data; } }第二步:定義一個(gè)抽象裝飾角色
abstract class Decorator implements Component {protected $component;public function __construct(Component $component){$this->component = $component;} }第三步:定義具體的裝飾類
// Json裝飾類 class JsonComponent extends Decorator{public function renderData(){return json_encode($this->component->renderData());} }// XML裝飾類 class XmlComponent extends Decorator{public function renderData(){return "this is Xml renderData method";} }第四步:測試
$component = new ConcreteComponent(["1", "2"]); var_dump($component->renderData());$jsonComponent = new JsonComponent($component); var_dump($jsonComponent->renderData());$xmlComponent = new XmlComponent($component); var_dump($xmlComponent->renderData());轉(zhuǎn)載于:https://www.cnblogs.com/qiye5757/p/10013048.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的敏捷软件开发学习笔记(四)之结构型设计模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分布式自增ID算法---雪花算法(Sno
- 下一篇: 【nodejs】让nodejs像后端mv