封裝
對事物的封裝是指,將事物進行抽象後,提供抽象概念的實現的具體方法。
- 定義:把物件的屬性和操作(或服務)結合為一個獨立的整體,並儘可能隱藏物件的內部實現細節。
- 好處
- 良好的封裝能夠減少耦合。
- 類內部的結構可以自由修改。
- 可以對成員進行更精確的控制。
- 隱藏資訊,實現細節。
- 方法
- Private
- Protected
- Public。
繼承
在一個現有類的基礎之上,增加新的方法或重寫已有方法,從而產生一個新類
private、protected、public三者許可權控制不能小於父類,可以擴大父類許可權
抽象類和介面
抽象類
一個類中,只要有一個抽象方法,這個類必須被宣告為抽象類。
抽象方法在子類中必須被重寫。
合理的對問題進行抽象,構造模型,將更容易通過程式設計來解決問題。
抽象類是一個程式設計概念,PHP 中叫 Abstract Classes。在設計模式中,抽象類不能夠被例項化/初始化,但是可以依靠具體類的 繼承 ( extends )來實現。
介面
PHP介面類 interface 就是一個類的領導者,指明方向,子類必須完成它指定方法。
PHP 也支援程式導向程式設計概念中的介面,PHP支援在介面中定義常量,但是不支援抽象變數。關鍵詞implements 實現介面。
介面中的所有方法都要求是抽象方法,所以就不需要在方法前使用 abstract 關鍵字標識了。而且在介面中也不需要顯式地使用 public 訪問許可權進行修飾,因為預設許可權就是 public 的,也只能是公有的。
抽象類vs介面
抽象類和介面的區別,不在於程式設計實現,而在於程式設計模式的不同。
一般來講,抽象用於不同的事物,而介面用於事物的行為。
- 對介面的使用方式是通過關鍵字 implements 來實現的,而對於抽象類的操作是使用類繼承的關鍵字 extends 實現的,使用時要特別注意。
- 介面沒有資料成員,但是抽象類有資料成員,抽象類可以實現資料的封裝。
- 介面沒有建構函式,抽象類可以有建構函式。
- 介面中的方法都是public型別,而抽象類中的方法可以使用 private、protected 或 public 來修飾。
- 一個類可以同時實現多個介面,但是隻能實現一個抽象類。
多型
多型是指在物件導向中能夠根據使用類的上下文來重新定義或改變類的性質和行為。
簡單來說:一個類例項的相同方法在不同情形有不同表現形式
php是弱型別語言,所以多型的體現十分模糊
繼承是多型得以實現的基礎
<?php
interface Eat {
function eatFish();
function eatMoss();
}
class Whale implements Eat {
public function eatFish() {
echo "Whale eats fish.\n";
}
public function eatMoss() {
echo "Whale doesn't eat fish\n";
}
}
class Carp implements Eat {
public function eatFish() {
echo "Carp doesn't eat moss.\n";
}
public function eatMoss() {
echo "Carp eats moss.\n";
}
}
$whale = new Whale();
$whale->eatFish();
$whale->eatMoss();
$carp = new Carp();
$carp->eatFish();
$carp->eatMoss();
?>
實現多型的三個必要條件
- 繼承:在多型中必須存在有繼承關係的子類和父類。
- 重寫:子類對父類中某些方法進行重新定義,在呼叫這些方法時就會呼叫子類的方法。
- 向上轉型:在多型中需要將子類的引用賦給父類物件,只有這樣該引用才能夠具備技能呼叫父類的方法和子類的方法。
S( Single-Resposibility Principle ): 單一職責原則
一個類,最好只做一件事,只有一個引起它的變化。
單一職責原則可以看做是低耦合、高內聚在物件導向原則上的引申,
將職責定義為引起變化的原因,以提高內聚性來減少引起變化的原因。
職責過多,可能引起它變化的原因就越多,這將導致職責依賴,相互之間就產生影響,從而大大損傷其內聚性和耦合度。 通常意義下的單一職責,就是指只有一種單一功能,不要為類實現過多的功能點,以保證實體只有一個引起它變化的原因。
專注,是一個人優良的品質; 同樣的,單一也是一個類的優良設計。 交雜不清的職責將使得程式碼看起來特別彆扭牽一髮而動全身,有失美感和必然導致醜陋的系統錯誤風險。
O( Open-Closed principle ): 開放封閉原則
軟體實體應該是可擴充套件的,而不可修改的。
也就是,對擴充套件開放,對修改封閉的。
對於開放封閉原則,它是物件導向所有原則的核心,軟體設計說到底追求的目標就是封裝變化、降低耦合,而開放封閉原則就是這一目標的最直接體現。
開放封閉原則,其核心思想是:軟體實體應該是可擴充套件的,而不可修改的。
也就是,對擴充套件開放,對修改封閉的。
因此,開放封閉原則主要體現在兩個方面:
- 對擴充套件開放,意味著有新的需求或變化時,可以對現有程式碼進行擴充套件,以適應新的情況。
- 對修改封閉,意味著類一旦設計完成,就可以獨立完成其工作,而不要對其進行任何嘗試的修改。
實現開開放封閉原則的核心思想就是對抽象程式設計,而不對具體程式設計,因為抽象相對穩定。
讓類依賴於固定的抽象,所以修改就是封閉的;
而通過物件導向的繼承和多型機制,又可以實現對抽象類的繼承,通過覆寫其方法來改變固有行為,實現新的擴充方法,所以就是開放的。
“需求總是變化”沒有不變的軟體,所以就需要用封閉開放原則來封閉變化滿足需求,同時還能保持軟體內部的封裝體系穩定,不被需求的變化影響。
L( Liskov-Substituion Principle ): 李氏替換原則
子類必須能夠替換其基類。
這一思想體現為對繼承機制的約束規範,只有子類能夠替換基類時, 才能保證系統在執行期內識別子類,這是保證繼承複用的基礎。
在父類和子類的具體行為中,必須嚴格把握繼承層次中的關係和特徵,將基類替換為子類,程式的行為不會發生任何變化。 同時,這一約束反過來則是不成立的,子類可以替換基類,但是基類不一定能替換子類。
Liskov替換原則,主要著眼於對抽象和多型建立在繼承的基礎上,因此只有遵循了Liskov替換原則,才能保證繼承複用是可靠地。
實現的方法是面向介面程式設計:
- 將公共部分抽象為基類介面或抽象類,通過Extract Abstract Class,在子類中通過覆寫父類的方法實現新的方式支援同樣的職責。
Liskov替換原則是關於繼承機制的設計原則,違反了Liskov替換原則就必然導致違反開放封閉原則。 Liskov替換原則能夠保證系統具有良好的擴充性,同時實現基於多型的抽象機制,能夠減少程式碼冗餘,避免執行期的型別判別。
I( Interface-Segregation Principle ): 介面隔離原則
使用多個小的專門的介面,而不要使用一個大的總介面
具體而言,介面隔離原則體現在:介面應該是內聚的,應該避免“胖”介面。
一個類對另外一個類的依賴應該建立在最小的介面上,不要強迫依賴不用的方法,這是一種介面汙染。
介面有效地將細節和抽象隔離,體現了對抽象程式設計的一切好處,介面隔離強調介面的單一性。而胖介面存在明顯的弊端,會導致實現的型別必須完全實現介面的所有方法、屬性等; 而某些時候,實現型別並非需要所有的介面定義,在設計上這是“浪費”,而且在實施上這會帶來潛在的問題,對胖介面的修改將導致一連串的客戶端程式需要修改,有時候這是一種災難。
在這種情況下,將胖介面分解為多個特點的定製化方法,使得客戶端僅僅依賴於它們的實際呼叫的方法,從而解除了客戶端不會依賴於它們不用的方法。
分離的手段主要有以下兩種:
- 委託分離,通過增加一個新的型別來委託客戶的請求,隔離客戶和介面的直接依賴,但是會增加系統的開銷。
- 多重繼承分離,通過介面多繼承來實現客戶的需求,這種方式是較好的。
D( Dependecy-Inversion Principle ): 依賴倒置原則
對於依賴倒置原則,其核心思想是:依賴於抽象。
具體而言就是高層模組不依賴於底層模組,二者都同依賴於抽象;
抽象不依賴於具體,具體依賴於抽象。
我們知道,依賴一定會存在於類與類、模組與模組之間。 當兩個模組之間存在緊密的耦合關係時,最好的方法就是分離介面和實現:
在依賴之間定義一個抽象的介面使得高層模組呼叫介面, 而底層模組實現介面的定義,以此來有效控制耦合關係, 達到依賴於抽象的設計目標。
抽象的穩定性決定了系統的穩定性,因為抽象是不變的, 依賴於抽象是物件導向設計的精髓,也是依賴倒置原則的核心。
依賴於抽象是一個通用的原則,而某些時候依賴於細節則是在所難免的, 必須權衡在抽象和具體之間的取捨,方法不是一層不變的。
依賴於抽象,就是對介面程式設計,不要對實現程式設計。
LSK學習筆記
本作品採用《CC 協議》,轉載必須註明作者和本文連結