設計模式學習

3333333_ 發表於 2020-11-21

格式亂了 看一看 http://note.youdao.com/s/a9HwjO0U

 

 

開閉原則

 

在物件導向程式設計領域中,開閉原則規定“軟體中的物件(類,模組,函式等等)應該對於擴充套件是開放的,但是對於修改是封閉的”,這意味著一個實體是允許在不改變它的原始碼的前提下變更它的行為。該特性在產品化的環境中是特別有價值的,在這種環境中,改變原始碼需要程式碼審查,單元測試以及諸如此類的用以確保產品使用質量的過程。遵循這種原則的程式碼在擴充套件時並不發生改變,因此無需上述的過程。

 

有具體程式碼 可檢視下面連結

https://www.cnblogs.com/Mishell/category/1631078.html

 

設計模式學習

 

 

1:學習設計模式的意義

 

學習設計模式的意義

1:更深入的理解物件導向的思想.

2:有利於開發出擴充套件性強的程式

3:面試時的重要考察方面

 

 

2:設計模式的概念

 

在軟體開發過程中,經常出現的典型場景的典型解決方案,稱為設計模式

 

 

生活中也有很多設計模式:

象棋招法,泡妞思路,

電影懸疑等等

 

 

 

2.1:動手造幾個設計模式

 

典型場景: 同學聚會

典型問題: 問你工資

典型解決: ?? 就那樣吧 還行

 

 

 

典型場景: QQ,屌絲,女神

典型問題: 女神,還沒睡?

典型解決: ?? 洗澡 呵呵

 

如何學習設計模式?

典型場景-->典型問題-->典型解決辦法

 

 

3:先說多型

 

 

為什麼先說多型?

答: 多型相對封裝與繼承,理解稍微複雜一些.

更重要的是,

通過PHP,Java多型的不同體現,體會靜態語言與動態語言的巨大差異

 

--而這個差異巨大,影響到設計模式.

對於動態語言,不可照搬java,C++中的設計模式

 

 

3.1:多型

 

 

多型(Polymorphism) 是一個生物學上的概念,

指同一特種的多種表現形態.

如:西伯利亞虎一般重210-260公斤,而孟加拉虎一般180-230公斤

 

在物件導向中,指某種物件例項的不同表現形態.

 

多型特點,在靜態語言中體現的更為明顯.

 

 

3.2:老虎爬樹

 

 

西伯利亞虎不能爬樹

孟加拉虎可以爬樹

 

那麼老虎,到底能否爬樹?

 

[

請看java與PHP演示

體會靜態與動態的巨大差異

]

 

 

 

4:簡單工廠模式 Factory

設計模式學習

 

 

4.1:分析問題

 

 

程式碼執行沒問題,呼叫沒問題!

 

但是:

你(客戶端,呼叫者)怎麼知道我有個DBmysql類, 和 DBMysqli類?

 

 

設計模式學習

 

1:客戶端應該只看到介面,不應該知道介面的實現.

體現封裝隔離原則.

 

2:無論客戶端,而是後端,都依賴於抽象介面,而非依賴於具體

 

 

4.2:解決問題

 

 

新增一個工廠,由工廠負責創造物件,並返回

 

 

設計模式學習

 

 

4.3:用簡單工廠後

 

 

 

設計模式學習

 

 

設計模式學習

 

4.4:用簡單工廠的真正意義

 

看似僅僅是把建立物件的過程包裝了一下,真正的變化在於"面向介面","隔離封裝",

客戶端只知介面,不知具體實現.

後端的實現,只知介面,不管前端誰呼叫

 

 

4.5:簡單工廠需改進之處

 

如果新增PDO方式,是否還要改Factory?

修改if/else分支?

 

違反開閉原則.

 

另:這個工廠如果分支足夠多,能幫你建立所有的類,形成"萬能工廠",物件導向設計中,不推薦一個類的功能過多.

 

我們可以把有相關關係的產品交由一個工廠生產

 

 

 

開閉原則

 

1988年,勃蘭特·梅耶(Bertrand Meyer)在他的著作

《物件導向軟體構造(Object Oriented Software Construction)》中提出了開閉原則,

它的原文是這樣:“Software entities should be open for extension,

but closed for modification”。

翻譯過來就是:“軟體實體應當對擴充套件開放,對修改關閉”。

 

通俗的說: 新增新類/介面等進來行,修改不行.

 

 

5.0:工廠方法 Factory Method

 

設計模式學習

工廠方法中,一個工廠生產多個零件,但零件的共同特點是--屬於一個產品.

 

即 此工廠可以生產產品,而非單獨的物件

 

 

6:單例模式 singleton 場景回放

 

設計模式學習

 

 

6.1:問題--如何確保只製造一個物件?

 

1:物件的產生,需要new或者clone

2:防止產生過多的物件,要防止new和clone

3:綜上,沒有物件時,允許new,並把物件快取.

下次直接返回該物件

 

6.2:解決效果

設計模式學習

 

 

 

6.3:模式解析

 

1:我學java時聽說有"懶漢式"和"餓漢式"單例模式

答:PHP的屬性不支援表示式,不支援"餓漢式"

 

2:php的單例,僅指程式中單例,不似java,在整個記憶體中單例

 

 

7:觀察者模式 Observer

 

設計模式學習

 

 

7.1:一般的思路

 

1:判斷選中的值

2:順序下來,根據值,修改內容區域

3:再修改廣告區域.

 

if(v == '男') {

內容區背景變灰

廣告區內容變成男人話題

} else if(v == '女'){

內容區背景變粉

廣告區內容變成女人話題

}

 

 

問題在哪兒?

1:讓你選擇時引起3個區域的變化,

是否要修改if/elseif部分

 

2:如果選擇女性樣式,但不要變粉,現在流行變紫色,是否又要修改if elseif部分?

 

問題在於: 控制邏輯與被操作物件耦合嚴重.

 

 

 

7.2:解決辦法

 

 

我們讓div物件觀察select的變化,select變化,就會通知道這兩個物件.

並引起這2個物件的變化,實現觀察者模式

 

設計模式學習

 

 

7.3:解決效果

 

 

select物件負責attach,detach,notifyObservers,與具體的物件變化解耦

 

 

設計模式學習

 

 

8:職責鏈模式 chain of resionbility

 

設計模式學習

 

8.1:一般做法

 

POST傳送資料,

PHP接收到資料,判斷舉報的級別.

 

if(粗口) {

啟動轉發給版主的流程

} else if(黃賭毒) {

啟動轉發給管理員的流程

} else {

啟動轉發給公安的流程

}

 

 

問題在哪兒:

1:如果新增了舉報級別,

要改if else 程式碼段.

 

2:如果流程內部有改動,也要到if else 程式碼段來操作.

 

總結:邏輯與執行操作的物件耦合嚴重.

 

 

8.2:解決辦法-職責鏈模式

 

 

設計模式學習

 

每個物件,儲存著對自己上級的引用,如果自己處理不了,交給上一級.

 

 

8.3:解決之後-職責鏈模式

 

 

設計模式學習

 

如下,只需要提交給版主即可,版主處理不了,會自動提交給上一級,直到處理完畢.

 

設計模式學習

 

 

9:策略模式

 

 

 

 

設計模式學習

 

 

9.1:一般的思路

 

 

根據傳遞的引數不同,進行加減乘除運算

 

 

設計模式學習

 

 

思考: 如果想增加取模運算又如何操作?

 

想一想簡單工廠方法,是否有些相似? 又有哪些不同?

 

通過介面,隔離封裝

通過繼承,適應變化

 

工廠模式,我們著眼於得到物件,並操作物件,

策略模式,我們著重得到物件某方法的執行結果

 

 

9.1:策略的實現 strategy

 

context物件

持有計算物件

並計算結果

直接返回

 

 

設計模式學習

 

 

10:裝飾器模式 decorator

 

 

這是一篇帖子

 

帖子的內容我寫好了,

三個部門的人員想控制他.

編輯組要添導讀文字

稽核組要去敏感字

市場部想在末尾加點廣告

我只是一篇帖子,由你們來處置吧

 

 

分析:三部分都操作該文章,

最先是編輯組,繼承該文章並新增了導讀方法

稽核組來了,繼承了該文章,新增去敏感字方法

市場部,繼承該文章,新增廣告方法

...

...

繼承的層次越來越深

 

能否不繼承,動態的增加物件的功能?

 

 

10.1:引入裝飾器模式

 

 

 

設計模式學習

 

11 介面卡模式

 

將各種截然不同的函式介面封裝成統一的API。

<?php header("Content-type:text/html;charset=utf-8"); // 介面卡模式 /** * 檢視天氣介面 */ class Tianqi { public static function show(){ $arr = array('tem'=>28,'wind'=>8,'sun'=>'windy','weekday'=>"週三"); return serialize($arr); } } //php客戶端呼叫 $b = unserialize(Tianqi::show()); echo "時間:".$b['weekday']."<br>"; echo "溫度:".$b['tem']."<br>"; echo "風力:".$b['wind']."<br>"; echo "太陽:".$b['sun']."<br>"; // 突然來了一批Java程式設計師,需要獲取天氣介面資料,但是他們不識別序列化後的資料,這時候應該怎麼辦呢? /** * 增加介面卡 */ class ADdapterTianqi extends Tianqi { public static function show() { $str = parent::show(); $arr = unserialize($str); return json_encode($arr); } } // 介面卡訪問資料 echo "<br><br>介面卡訪問資料:<br>"; $b = json_decode(ADdapterTianqi::show(),true); echo "時間:".$b['weekday']."<br>"; echo "溫度:".$b['tem']."<br>"; echo "風力:".$b['wind']."<br>"; echo "太陽:".$b['sun']."<br>";

 

12橋接模式

 

設計模式學習

 

整合的話 就是NxN個類

 

如果是橋接 就是 N+N個類

 

<?php header("Content-type:text/html;charset=utf-8"); abstract class msg{ protected $send = null; public function __construct($send){ $this->send = $send; } abstract function msg($content); function send($to, $content){ $content = $this->msg($content); $this->send->send($to, $content); } } /** * 普通訊 */ class ZnMsg { public function send($to, $content) { echo "給".$to."傳送站內信:<br>".$content; } } /** * email信 */ class EmailMsg { public function send($to, $content) { echo "給".$to."傳送Email:<br>".$content; } } /** * sms信 */ class SmsMsg { public function send($to, $content) { echo "給".$to."傳送簡訊:<br>".$content; } } // 內容分為普通,加急,特急三種程度 /** * 普通 */ class CommonInfo extends msg { public function msg($content) { return "普通:".$content."<br>"; } } /** * 加急 */ class WarnInfo extends msg { public function msg($content) { return "加急:".$content."<br>"; } } /** * 特急 */ class DangerInfo extends msg { public function msg($content) { return "特急:".$content."<br>"; } } $DangerInfo = new DangerInfo(new EmailMsg()); $DangerInfo->send('小明','家裡著火了'); $WarnInfo = new WarnInfo(new EmailMsg()); $WarnInfo->send('小明','下午參加畢業典禮');