設計原則 ① : 按接口而不是按實現來編程php
按接口而不是按實現編程是指,要將變量設置爲一個抽象類或接口數據類型的實例,
而不是一個具體實現的實例。這樣能夠將設計與實現解耦合。
有些語言變量聲明包含數據類型,例如在一個強類型語言中能夠有如下聲明:算法
<?php Interface IAlpha //接口名 class AlphaA implements IAlpha //AlphaA的數據類型爲IAlpha Variable useAlpha //聲明類型爲IAlpha,例如(IAlpha useAlpha) useAlpha //實例化新的AlphaA() ?>
若是沒有強類型機制,能夠利用代碼提示保證按接口編程,以上一節寫過的一段代碼爲例編程
<? //useProduct.php class useProduct{ public function __construct(){ $apple = new FruitStore(); $book = new BookStore(); $this->doInterface($apple); $this->doInterface($book); } function doInterface(IProduct $product){ //這裏的IProduct $product就是一種類型提示,方法類型提示爲接口IProduct //不管程序變得多複雜都不要緊,只要保證接口 //就能夠作出任意的修改和增補,不會破壞程序的其它部分 echo $product->apples(); echo $product->books(); } } $worker = new useProduct(); ?>
設計原則 ② : 應當優先選擇對象組合而不是類繼承設計模式
有的OOP程序猿認爲對象重用就等同於繼承,一個類能夠有大量屬性和方法,擴展這個類就能夠重用全部那些對象元素,而不用從新編寫代碼。能夠擴展類,再增長必要的新屬性和方法。下面將舉一個例子說明對象組合和類繼承之間的區別。app
首先是繼承的代碼框架
<?php //Domath.php class DoMath{ private $sum; private $quotient; public function simpleAdd($first,$second){ $this->sum = ( $first + $second ); return $this->sum; } public function simpleDivide($divided, $divisor){ $this->quotient = ( $dividend / $divisor); return $this->quotient; } } ?>
<?php //InheritMath.php include_once('DoMath.php'); class InheritMath extends DoMath{ private $textOut; private $fullFace; public function numToText($num){ $this->textOut = (string)$num; return $this->textOut; } public function addFace($face,$msg){ $this->fullFace = "<strong>" . $face . "</strong> : " .$msg; return $this->fullFace; } } ?>
<?php //ClientInherit include_once('InheritMath.php'); class ClientInherit{ private $added; private $divided; private $textNum; private $output; public function __construct(){ $family = new InheritMath(); $this->added = $family->simpleAdd(40,60); $this->divided = $family->simpleDivided($this->added,25); $this->textNum = $family->numToText($this->divided); $this->output = $family->addFace("Your results",$this->textNum); echo $this->output; } } $worker = new ClientInherit(); ?>
下面是組合,Client類使用兩個不一樣的類,分別包含兩個方法,DoMath類等同於繼承例子中的父類,因此首先是DoText類ide
<?php //DoText.php //與InheritMath類類似,事實也如此,不過他沒有繼承DoMath類 class DoText{ private $textOut; private $fullFace; public function numToText($num){ $this->textOut = (string)$num; return $this->textOut; } public function addFace($face,$msg){ $this->fullFace = "<strong>" . $face . "</strong> : " .$msg; return $this->fullFace; } } ?>
<?php //ClientCompost.php include_once('DoMath.php'); include_once('DoText.php'); class ClientCompose{ private $added; private $divided; private $textNum; private $output; public function __construct{ $useMath = new DoMath(); $useText = new DoText(); $this->added = $useMath->simpleAdd(40,60); $this->divided = $useMath->simpleDivide($this->added,25); $this->textNum = $useText->numToText($this->divided); $this->output = $useText->addFace("Your results",$this->textNum); echo $this->output; } } ?>
Client類必須包含多個類,看起來更勝一籌,不過在較大的程序中,組合能夠避免維護多個繼承層次上的各個子類,並且還能夠避免可能致使的錯誤。例如父類的一個改變會逐級向下傳遞給子類實現,這可能會影響子類使用的某個算法。
要避免使用繼承造成一長串子類、孫子類、曾孫子類,設計模式方法建議使用淺繼承。post
設計模式是按照做用和範圍來組織的
設計模式按做用能夠分爲如下3類ui
建立型this
顧名思義,就是用來建立對象的模式,更確切地講,這些模式是對實例化過程的抽象,
若是程序愈來愈以來組合,就會減小對硬編碼實例化的依賴,而更多地以來於一組靈
活的行爲,這些行爲能夠組織到一個更爲複雜的集合中,建立型模式提供了一些方法
來封裝系統使用的具體類的有關知識,還能夠隱藏實例建立和組合的相關信息
結構型
這些模式所關心的是組合結構應當保證結構化。結構型類模式採用繼承來組合接口或實現。結構型對象模式則描述了組合對象來創建新功能的方法。瞭解結構型模式對於理解和使用相互關聯的類(做爲設計模式中的參與者)頗有幫助
行爲型
到目前爲止,絕大多數模式都是行爲型對象,這些模式的核心是算法和對象之間職責的分配。這些設計模式描述的不僅是對象或類的模式,它們還描述了類和對象之間的通訊模式
設計模式按範圍能夠分爲如下2類
類
在兩類範圍中,第一類範圍是類。這些類模式的重點在於類及其子類之間的關係,類模式中的關係是經過繼承建成
對象
儘管大多數設計模式都屬於對象範圍,不過與類範圍中的那些模式同樣,不少模式也會使用繼承。對象設計模式與類模式的區別在於,對象模式強調的是能夠在運行時改變的對象,所以這些模式更具動態性。
設計模式做用、範圍和變化
與框架相比,設計模式是體系結構中更小的元素,也更爲抽象,另外設計模式沒有框架那麼 特定。所以,設計模式更可重用,也比框架靈活。 框架的有點與模板有些相似:它們更有指示性,能夠更清楚地指示所解決問題的結構。爲了 提供這種易用性,它們不得不放棄了體系結構的靈活性。若是使用框架,構建應用會快得多, 可是所構建的應用會受到框架自己的約束。框架能夠包含面向對象結構,一般框架是分層的, 每一層處理更大設計中的一個方面。框架的一些特性在設計模式中也有體現,不過,設計模 式沒有框架那麼特定和具體,也沒有那麼龐大
概念:UML(the Unified Modeling Language——統一建模語言),引入了一個強大的 圖形化的語法來描述面向對象系統
類是類圖的主要部分,類用帶有類名的方框來描述。
上圖中,圖1最早顯示的是類的名稱,下面兩部分是可選的,用於顯示類名以外的信息。 能夠發現圖1已經足夠描述一些類,並不是總要在類圖中顯示每一個屬性和方法,甚至不須要 顯示每一個類 一般用斜體的類名(圖2),或者增長{abstract}到類名下(圖3)來表示該類是抽象 類。 第一種方法比第一種方法經常使用,可是當你作筆記時第二種方法更有用 接口定義的方式和類相同,但接口必須使用一個衍型(UML的一個擴展),如樓下所示
通常來講,屬性用於描述一個類的屬性,屬性直接列在類名下面的格子中,如樓下所示
屬性前面的符號表示該屬性可見性的級別或者是訪問控制
冒號用於分隔屬性名和它的類型及默認值(默認值爲可選項,能夠不提供)
Again:只要提供必要的信息,不須要全部細節
操做用於描述類方法,操做和屬性使用了類似的語法
(1)可見性符號放在方法名以前 (2)參數列表包含在括號之中 (3)方法若是有返回類型的話,用冒號來描述 (4)參數用逗號來分隔,而且遵照屬性語法 (5)參數名和它的數據類型間用冒號分隔
以下圖所示
繼承關係用從子類到父類的一條線來表示,線的頂端有一個空心閉合箭頭
UML用"實現"來描述接口和實現接口的類之間的關係,若是ShopProduct類實現了Chargeable接口,就能夠加入類圖中,如圖所示
一個類的屬性保存了對另外一個類的一個實例或多個實例的引用時,就產生了關聯
下圖中爲輛各種創建模型,並建立類之間的關聯,圖中指出Teacher對象擁有一個或多個對Pupil對象的引用,或者Pupil對象擁有一個或多個對Teacher對象的引用
咱們能夠用剪頭來描述關聯的方向,若是Teacher類擁有Pupil類的一個實例,可是Pupil類並無Teacher類的實例,那咱們可讓關聯剪頭從Teacher類指向Pupil類,稱爲"單向關聯"
若是兩個類剪互相擁有對方的引用,能夠用一個雙向剪頭來描述這種"雙向關聯"關係
也能夠在關聯中指定一個類的實例被其它類引用的次數,能夠經過把次數或者範圍放在每一個類旁邊來講明。用星號(*)表示任意次數,以下圖所示,Teacher對象擁有零個或多個Pupil對象
都描述了一個類長期持有其它類的一個或多個實例的狀況,經過聚合和組合,被 引用的對象實例成爲引用對象的一部分。 聚合關係用一條以空心菱形開頭的線來講明,以下圖所示,定義了兩個類, SchoolClass和Pupil, SchoolClass類聚合了Pupil (意思就是學生組成了班級,若是咱們要刪除一個學校類,不須要同時刪除)
組合是一個更強的關係,在組合中,被包含對象只能被它的容器所引用,當容器刪除 時,她應該也被刪除,組合關係用相似聚合關係的方式描述,但它的菱形是實心的 下圖中,Person類持有對SocialSecurityData對象的引用,而SocialSecurityData 對象實例屬於包含它的Person對象
使用:即依賴關係,並不是類之間的長久關係 下圖中,Report類使用了ShopProductWriter對象,這種使用關係由一條鏈接兩個類 的虛線和開放剪頭表示。Report類沒有把ShopProductWriter保存爲類中的屬性, ShopProductWriter對象則將一組ShopProduct對象做爲屬性
註解:解釋類處理任務的過程(類圖只能捕捉系統結構) 以下圖,Report對象使用了ShopProductWriter,可是不知道具體如何實現, 咱們使用了註解來補充說明
如圖所示,註解由一個這叫的方框組成,一般包含僞代碼片斷
時序圖是基於對象而不是基於類的,用於爲系統中過程化的行爲建模。 以下,爲Report對象輸出產品數據的過程建模,從左到右展示了系統的參與者 咱們值使用類名來標記對象,若是圖中有同一個類的多個對象實例在獨立工做, 可使用label:class(例如product1 : ShopProduct)格式來包含對象名
下圖咱們從上到下展現了該過程每一個對象的生命週期
垂直的虛線是生命線,展現了系統中對象的生命週期,生命線上的矩形說明了過程當中的 焦點,即某個對象的激活期。 顯示對象間傳遞的消息,這個圖才更容易被看懂,以下
箭頭表示消息從一個對象傳遞到另外一個對象,返回值通常不寫。 每一個消息都用相關的方法調用來標記,例如方括號說明一個條件,像 {okToPrint} write() 只有在必定條件下write纔會被執行 星號用於表示一個重複的操做,能夠在方括號中進一步說明 *{for each ShopProduct} write() 該圖含義:Report對象得到一個來自ProductStore對象的ShopProduct對象列表。 Report對象傳遞這個ShopProduct列表給一個ShopProcuctWriter對象,而 ShopProductWriter存放了對ShopProduct對象的引用(雖然咱們只能從圖中推斷 出折點)ShopProductWriter對象爲它引用的每一個ShopProduct對象調用ShopProduct:: getSummaryLine(),並添加執行結果到最終的輸出結果中
本文筆記參考書籍:
《深刻PHP:面向對象、模式與實踐》第4章
《Learning-PHP設計模式》第4章
下節:Chap3:建立型設計模式————工廠方法設計模式