摘要:面向?qū)ο笤O(shè)計的五大原則單一職責(zé)原則接口隔離原則開放封閉原則替換原則依賴倒置原則。主要是針對繼承的設(shè)計原則,繼承與派生多態(tài)是的主要特性。
面向?qū)ο笤O(shè)計的五大原則:單一職責(zé)原則、接口隔離原則、開放-封閉原則、替換原則、依賴倒置原則。這些原則主要是由Robert C.Martin在《敏捷軟件開發(fā)——原則、方法、與實踐》一書中總結(jié)出來,這五大原則也是23種設(shè)計模式的基礎(chǔ)。
單一職責(zé)原則 Single Pesponsibility Principle, SRP
在MVC框架中,對于表單插入數(shù)據(jù)庫字段過濾與安全檢查應(yīng)該是放在control層處理還是model層處理,這類問題都可以歸到單一職責(zé)的范圍。
單一職責(zé)有兩個含義:
避免相同的職責(zé)分散到不同的類中
一個類承擔(dān)太多職責(zé)
遵守SRP的好處:
減少類之間的耦合
提高類的復(fù)用性
在實際代碼開發(fā)中的應(yīng)用:工廠模式、命令模式、代理模式等。
工廠模式(Factory)允許在代碼執(zhí)行時實例化對象。之所以被稱為工廠模式是因為它負(fù)責(zé)“生產(chǎn)”對象。以數(shù)據(jù)庫為例,工廠需要的就是根據(jù)不同的參數(shù),生成不同的實例化對象。它只負(fù)責(zé)生產(chǎn)對象,而不負(fù)責(zé)對象的具體內(nèi)容。
定義一個適配器接口:
定義MySQL數(shù)據(jù)庫操作類:
_dbLink = @mysql_connect($config->host . (empty($config->port) ? "" : ":" . $config->port), $config->user, $config->password, true)) { if(@mysql_select_db($config->database, $this->_dbLink)){ if($config->charset){ mysql_query("SET NAMES "{$config->charset}"", $this->_dbLink); } return $this->_dbLink; } } //數(shù)據(jù)庫異常 throw new DbException(@mysql_error($this->_dbLink)); } /** * 執(zhí)行數(shù)據(jù)庫查詢 * @param string $query 數(shù)據(jù)庫查詢SQL字符串 * @param mixed $handle 連接對象 * @return resource */ public function query($query, $handle) { if ($resource = @mysql_query($query, $handle)) { return $resource; } } } ?>
SQLite數(shù)據(jù)庫操作類:
_dbLink = sqlite_open($config->file, 0666, $error)) { return $this->_dbLink; } throw new DbException($error); } /** * 執(zhí)行數(shù)據(jù)庫查詢 * @param string $query 數(shù)據(jù)庫查詢SQL字符串 * @param mixed $handle 連接對象 * @return resource */ public function query($query, $handle) { if ($resource = @sqlite_query($query, $handle)) { return $resource; } } } ?>
定義一個工廠類,根據(jù)傳入不同的參數(shù)生成需要的類:
調(diào)用:
$db = sqlFactory::factory("MySQL"); $db = sqlFactory::factory("SQLite");
命令模式分離“命令的請求者”和“命令的實現(xiàn)者”方面的職責(zé)。
模擬服務(wù)員與廚師的過程:
cook = $cook; } public function execute(){ $this->cook->meal();//把消息傳遞給廚師,讓廚師做飯 } } class DrinkCommand implements Command { private $cook; //綁定命令接受者 public function __construct(cook $cook){ $this->cook = $cook; } public function execute(){ $this->cook->drink(); } } ?>
模擬顧客與服務(wù)員的過程:
mealCommand = $mealCommand; $this->drinkCommand = $drinkCommand; } public function callMeal(){ $this->mealCommand->execute(); } public function callDrink(){ $this->drinkCommand->execute(); } } ?>
實現(xiàn)命令模式:
$control = new cookControl; $cook = new cook; $mealCommand = new MealCommand($cook); $drinkCommand = new DrinkCommand($cook); $control->addCommand($mealCommand, $drinkCommand); $control->callMeal(); $control->callDrink();
接口隔離原則 Interface Segregation Principle,ISP
接口隔離原則(Interface Segregation Principle,ISP)表明客戶端不應(yīng)該被強(qiáng)迫實現(xiàn)一些不會使用的接口,應(yīng)該把胖接口分組,用多個接口代替它,每個接口服務(wù)于一個子模塊。簡單地說,就是使用多個專門的接口比使用單個接口要好很多。
ISP主要觀點:
1.一個類對另外一個類的依賴性應(yīng)當(dāng)是建立在最小接口上的。
ISP可以達(dá)到不強(qiáng)迫客戶(接口使用者)依賴于他們不用的方法,接口的實現(xiàn)類應(yīng)該只呈現(xiàn)為單一職責(zé)的角色(遵守SRP原則)。
ISP可以降低客戶之間的相互影響——當(dāng)某個客戶程序要求提供新的職責(zé)(需求變化)而迫使接口發(fā)生變化時,影響到其他客戶程序的可能性會最小。
2.客戶端程序不應(yīng)該依賴它不需要的接口方法(功能)。
ISP強(qiáng)調(diào)的是接口對客戶端的承諾越少越好,并且要做到專一。
接口污染就是為接口添加不必要的職責(zé)。“接口隔離”其實就是定制化服務(wù)設(shè)計的原則。使用接口的多重繼承實現(xiàn)對不同的接口的組合,從而對外提供組合功能——達(dá)到“按需提供服務(wù)”。
對于接口的污染,使用下面兩種處理方式:
利用委托分離接口。
利用多繼承分離接口。
委托模式中,有兩個對象參與處理同一個請求,接受請求的對象將請求委托給另一個對象來處理,如策略模式、代理模式等都應(yīng)用到了委托的概念。
開放-封閉原則
隨著軟件系統(tǒng)的規(guī)模不斷增大,軟件系統(tǒng)的維護(hù)和修改的復(fù)雜性不斷提高,這種困境促使法國工程院士Bertrand Meyer在1998年提出了“開放-封閉”(Open-Close Principle, OCP)原則,基本思想是:
Open(Open for extension)模塊的行為必須是開放的、支持?jǐn)U展的,而不是僵化的。
Closed(Closed for modification)在對模塊的功能進(jìn)行擴(kuò)展時,不應(yīng)該影響或大規(guī)模地影響已有的程序模塊。
換句話說,也就是要求開發(fā)人員在不修改系統(tǒng)中現(xiàn)有功能代碼(源代碼或二進(jìn)制代碼)的前提下,實現(xiàn)對應(yīng)用系統(tǒng)的軟件功能的擴(kuò)展。用一句話概括就是:一個模塊在擴(kuò)展性方面應(yīng)該是開放的而在更改性方面應(yīng)該是封閉的。
開放-封閉能夠提高系統(tǒng)的可擴(kuò)展性和可維護(hù)性,但這也是相對的。
以播放器為例,先定義一個抽象的接口:
interface Process { public function process(); }
然后對此接口進(jìn)行擴(kuò)展,實現(xiàn)解碼和輸出的功能:
class playerEncode implements Proess { public function process(){ echo "encode "; } } class playerOutput implements Process { public function process(){ echo "output "; } }
對于播放器的各種功能,這里是開放的。只要你遵守約定,實現(xiàn)了process接口,就能給播放器添加新的功能模塊。
接下來為定義播放器的線程調(diào)度管理器,播放器一旦接收到通知(可以是外部單擊行為,也可以是內(nèi)部的notify行為),將回調(diào)實際的線程處理:
class playProcess { private $message = null; public function __construct(){ } public function callback(Event $event){ $this->message = $event->click(); if($this->message instanceof Process){ $this->message->process(); } } }
具體的產(chǎn)品出來了,在這里定義一個MP4類,這個類是相對封閉的,其中定義事件的處理邏輯:
class MP4 { public function work(){ $playProcess = new playProcess(); $playProcess->callback(new Event("encode")); $playProcess->callback(new Event("output")); } }
最后為事件分揀的處理類,此類負(fù)責(zé)對事件進(jìn)行分揀,判斷用戶或內(nèi)部行為,以產(chǎn)生正確的“線程”,供播放器內(nèi)置的線程管理器調(diào)度:
class Event { private $m; public function __construct($me){ $this->m = $me; } public function click(){ switch($this->m){ case "encode": return new playerEncode(); break; case "output": return new playerOutput(); break; } } }
運(yùn)行:
$mp4 = new MP4; $mp4->work(); //打印結(jié)果 encode output
如何遵守開放-封閉原則
實現(xiàn)開放-封閉的核心思想就是抽象編程的核心思想就是對抽象編程,而不是對具體編程,因為抽象相對穩(wěn)定。讓類依賴于固定的抽象,這樣的修改就是封閉的;而通過面向?qū)ο蟮?b>繼承和多態(tài)機(jī)制,可以實現(xiàn)對抽象體的繼承,通過覆寫其方法來改變固有的行為,實現(xiàn)新的擴(kuò)展方法,所以對于擴(kuò)展就是開放的。
1.在設(shè)計方面充分應(yīng)用“抽象”和封裝的思想。
一方面就是要在軟件系統(tǒng)中找出各種可能的“可變因素”,并將之封裝起來;另一方面,一種可變性因素不應(yīng)當(dāng)散落在多個不同代碼模塊中,而應(yīng)當(dāng)被封裝到一個對象中。
2.在系統(tǒng)功能編程實現(xiàn)方面應(yīng)用面向接口編程。
當(dāng)需求發(fā)生變化時,可以提供該接口新的實現(xiàn)類,以求適應(yīng)變化。
面向接口編程要求功能類實現(xiàn)接口,對象聲明為接口類型。再設(shè)計模式中,裝飾模式比較明顯地用到OCP。
替換原則
替換原則也稱里氏替換原則(Liskov Substitution Principle, LSP)的定義和主要思想如下:由于面向?qū)ο缶幊碳夹g(shù)中的繼承在具體的編程中過于簡單,在許多系統(tǒng)的設(shè)計和編程實現(xiàn)中,我們并沒有認(rèn)真地、理性地思考應(yīng)用系統(tǒng)中各個類之間的繼承關(guān)系是否合適,派生類是否能正確地對其基類中的某些方法進(jìn)行重寫等問題。因此經(jīng)常出現(xiàn)濫用繼承或者錯誤地進(jìn)行了繼承等現(xiàn)象,給系統(tǒng)的后期維護(hù)帶來不少麻煩。
LSP指出:子類型必須能夠替換掉它們的父類型,并出現(xiàn)在父類能夠出現(xiàn)的任何地方。
LSP主要是針對繼承的設(shè)計原則,繼承與派生(多態(tài))是OOP的主要特性。
如何遵守LSP設(shè)計原則:
父類的方法都要在子類中實現(xiàn)或重寫,并且派生類只實現(xiàn)其抽象類中聲明的方法,而不應(yīng)當(dāng)給出多余的方法定義或?qū)崿F(xiàn)。
在客戶段程序中只應(yīng)該使用父類對象而不應(yīng)當(dāng)直接使用子類對象,這樣可以實現(xiàn)運(yùn)行期綁定(動態(tài)綁定)。
如果A、B兩個類違反了LSP的設(shè)計,通常的做法是創(chuàng)建一個新的抽象類C,作為兩個具體類的超類,將A和B的共同行為移到C中,從而解決A和B行為不完全一致的問題。
依賴倒置原則 Dependence Inversion Principle, DIP
依賴倒置簡單地講就是將依賴關(guān)系倒置為依賴接口,具體概念如下:
上層模塊不應(yīng)該依賴于下層模塊,它們共同依賴于一個抽象(父類不能依賴子類,它們都要依賴抽象類)。
抽象不能依賴于具體,具體應(yīng)該依賴于抽象。
為什么要依賴接口?因為接口體現(xiàn)對問題的抽象,同時由于抽象一般是相對穩(wěn)定的或者是相對變化不頻繁的,而具體是易變的。因此,依賴抽象是實現(xiàn)代碼擴(kuò)展和運(yùn)行期內(nèi)綁定(多態(tài))的基礎(chǔ):只要實現(xiàn)了該抽象類的子類,都可以被類的使用者使用。
working(); } } class workB { private $e; public function set(employee $e){ $this->e = $e; } public function work(){ $this->e->working(); } } $worka = new workA; $worka->work(); $workb = new workB; $workb->set(new teacher()); $workb->work();
在workA中,work方法依賴于teacher實現(xiàn);在workB中,work轉(zhuǎn)而依賴于抽象,這樣可以把需要的對象通過參數(shù)傳入。
在workB中,teacher實例通過setter方法傳入,從而實現(xiàn)了工廠模式。由于這樣的是實現(xiàn)是硬編碼的,為了實現(xiàn)代碼的進(jìn)一步擴(kuò)展,把這個依賴關(guān)系寫在配置文件里,指明workB需要一個teacher對象,專門由一個程序檢測配置是否正確(如所依賴的類文件是否存在)以及加載配置中所依賴的實現(xiàn),這個檢測程序,就稱為IOC容器。
IOC(Inversion Of Control)是依賴倒置原則(Dependence Inversion Principle, DIP)的同義詞。依賴注入(DI)和依賴查找(DS)是IOC的兩種實現(xiàn)。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/28428.html
摘要:設(shè)計原則梳理,參考核心技術(shù)與最佳實踐敏捷開發(fā)原則模式與實踐,文章面向?qū)ο笤O(shè)計的五大原則設(shè)計模式原則單一職責(zé)原則定義特性僅有一個引起類變化的原因一個類只承擔(dān)一項職責(zé)職責(zé)變化的原因避免相同的職責(zé)分散到不同的類,功能重復(fù)問題一個類承擔(dān)的職責(zé)過多, PHP設(shè)計原則梳理,參考《PHP核心技術(shù)與最佳實踐》、《敏捷開發(fā)原則、模式與實踐》,文章PHP面向?qū)ο笤O(shè)計的五大原則、設(shè)計模式原則SOLID 單一...
摘要:如果看不懂的話,可以在評論區(qū)中提問,我會第一時間回答你無論何時我一直都在嗯哼該文章屬于編程中的那些經(jīng)典套路設(shè)計模式匯總系列 在正式閱讀前,我先談?wù)勎覀冊撚檬裁醋藙莺托膽B(tài)學(xué)習(xí)設(shè)計模式: 如果你還沒有過多的編程經(jīng)驗(泛指半年以下),我建議你把它當(dāng)做小說來看,能看懂多少是多少,因為半年以下經(jīng)驗的程序員用到設(shè)計模式的情況只會出現(xiàn)在面試上,至于實際工作中?相對來說這部分不會由你負(fù)責(zé)。 如果你已...
摘要:前言本章我們要講解的是五大原則語言實現(xiàn)的第篇,里氏替換原則。因此,違反了里氏替換原則。與行為有關(guān),而不是繼承到現(xiàn)在,我們討論了和繼承上下文在內(nèi)的里氏替換原則,指示出的面向?qū)ο蟆? 前言 本章我們要講解的是S.O.L.I.D五大原則JavaScript語言實現(xiàn)的第3篇,里氏替換原則LSP(The Liskov Substitution Principle )。英文原文:http://fre...
摘要:簡單工廠模式就是遵循了這一原則,它讓不同職責(zé)的類各司其職。重點來了,簡單工廠模式的不足但是簡單工廠模式有一個不足,雖然它遵循了單一職責(zé)原則,但它違反了另一條同樣很重要的原則開放封閉原則。 該文章屬于《編程中的那些經(jīng)典套路——設(shè)計模式匯總》系列,并且以下內(nèi)容基于語言PHP 面向?qū)ο笪宕笤瓌t中有一點非常重要的原則:單一職責(zé)原則。 簡單工廠模式就是遵循了這一原則,它讓不同職責(zé)的類各司其職。 ...
摘要:,開始我們的第一篇單一職責(zé)。通過解耦可以讓每個職責(zé)工更加有彈性地變化。關(guān)于本文本文轉(zhuǎn)自大叔的深入理解系列。深入理解系列文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載,整理等各類型文章,原文是大叔的一個非常不錯的專題,現(xiàn)將其重新整理發(fā)布。 前言 Bob大叔提出并發(fā)揚(yáng)了S.O.L.I.D五大原則,用來更好地進(jìn)行面向?qū)ο缶幊?,五大原則分別是: The Single Responsibility Princi...
閱讀 739·2021-11-18 10:02
閱讀 3670·2021-09-02 10:21
閱讀 1776·2021-08-27 16:16
閱讀 2091·2019-08-30 15:56
閱讀 2440·2019-08-29 16:53
閱讀 1399·2019-08-29 11:18
閱讀 2984·2019-08-26 10:33
閱讀 2668·2019-08-23 18:34