面向?qū)ο缶幊瘫焕簿褪俏覀兂Uf的OOP,其實(shí)是面向?qū)ο蟮囊徊糠至潞!C嫦驅(qū)ο笠还灿?個(gè)部分:面向?qū)ο蠓治觯∣OA)脸哀、面向?qū)ο笤O(shè)計(jì)(OOD)、面向?qū)ο缶幊蹋∣OP)扭吁。
面向?qū)ο蟮娜筇匦允?封裝撞蜂、"多態(tài)"、"繼承"侥袜,五大原則是"單一職責(zé)原則"蝌诡、"開放封閉原則"、"里氏替換原則"枫吧、"依賴倒置原則"浦旱、"接口分離原則"。
一九杂、封裝
1颁湖、定義:
封裝就是把抽象出的數(shù)據(jù)和對數(shù)據(jù)的操作封裝在一起,數(shù)據(jù)被保護(hù)在內(nèi)部尼酿,程序的其他部分只有通過被授權(quán)的操作(成員方法)才能對數(shù)據(jù)進(jìn)行操作爷狈。
封裝是面向?qū)ο蟮奶卣髦唬菍ο蠛皖惛拍畹闹饕匦浴?簡單的說裳擎,一個(gè)類就是一個(gè)封裝了數(shù)據(jù)以及操作這些數(shù)據(jù)的代碼的邏輯實(shí)體。在一個(gè)對象內(nèi)部思币,某些代碼或某些數(shù)據(jù)可以是私有的鹿响,不能被外界訪問。通過這種方式谷饿,對象對內(nèi)部數(shù)據(jù)提供了不同級別的保護(hù)惶我,以防止程序中無關(guān)的部分意外的改變或錯(cuò)誤的使用了對象的私有部分。
2博投、封裝的作用
1)使用者只關(guān)心類能夠提供的功能绸贡,而不必關(guān)心功能實(shí)現(xiàn)的細(xì)節(jié)!(封裝方法)
2)對用戶的數(shù)據(jù)進(jìn)行控制毅哗,防止設(shè)置不合法數(shù)據(jù)听怕,控制返回給用戶的數(shù)據(jù)(屬性封裝+set/get方法)
3、如何實(shí)現(xiàn)封裝
1)方法的封裝
對于一些只在類內(nèi)部使用的方法虑绵,而不像對外部提供使用尿瞭。那么,這樣的方法我們可以使用private進(jìn)行私有化處理翅睛。
private function formatName(){} //這個(gè)方法僅僅能在類內(nèi)部使用$this調(diào)用
function showName(){
$this -> formatName();
}
2)屬性的封裝+set/get方法
為了控制屬性的設(shè)置以及讀取声搁,可以將屬性進(jìn)行私有化處理黑竞,并要求用戶通過我們提供的set/get方法進(jìn)行設(shè)置/獲取
private $age;
function setAge($age){
$this->age = $age;
}
function getAge(){
return $this->age;
}
$object->getAge();
$object->setAge(12);
3)屬性的封裝+魔術(shù)方法
private $age;
function __get($key){
return $this->$key;
}
function __set($key,$value){
$this->$key=$value;
}
$對象->age; // 訪問對象私有屬性時(shí),自動(dòng)調(diào)用__get()魔術(shù)方法疏旨,并且將訪問的屬性名傳給__get()方法很魂;
$對象->age=12; // 設(shè)置對象私有屬性時(shí),自動(dòng)調(diào)用__set()魔術(shù)方法檐涝,并且將設(shè)置的屬性名以及屬性值傳給__set()方法莫换;
4、關(guān)于封裝的魔術(shù)方法
1)__set($key,$value):給類私有屬性賦值時(shí)自動(dòng)調(diào)用骤铃,調(diào)用時(shí)給方法傳遞兩個(gè)參數(shù):需要設(shè)置的屬性名拉岁、屬性值;
2)__get($key):讀取類私有屬性時(shí)自動(dòng)調(diào)用惰爬,調(diào)用時(shí)給方法傳遞一個(gè)參數(shù):需要讀取的屬性名喊暖;
3)__isset($key)::當(dāng)使用 isset()函數(shù)或者empty()函數(shù) 判斷屬性是否存在或者是否為空的時(shí)候會(huì)自動(dòng)觸發(fā)。
--------類外部使用isset();檢測私有(private)屬性撕瞧,默認(rèn)是檢測不到的陵叽。false
--------所以,我們可以使用__isset();函數(shù)丛版,在自動(dòng)調(diào)用時(shí)巩掺,返回內(nèi)部檢測結(jié)果。
function __isset($key){
return isset($this->$key);
}
//當(dāng)外部使用isset($對象名->私有屬性);檢測時(shí)页畦,將自動(dòng)調(diào)用上述__isset()返回的結(jié)果胖替!
4)__unset($key):外部使用unset()函數(shù)刪除私有屬性時(shí),自動(dòng)調(diào)用豫缨;
function __unset($key){
unset($this->$key);
}
//當(dāng)外部使用unset($對象名->私有屬性);刪除屬性時(shí)独令,自動(dòng)將屬性名傳給__unset(),并交由這個(gè)魔術(shù)方法處理。
二好芭、繼承
1燃箭、定義:
繼承是指可以讓某個(gè)類型的對象獲得另一個(gè)類型的對象的屬性的方法,它支持按級分類的概念。
繼承是指這樣一種能力:它可以使用現(xiàn)有類的所有功能舍败,并在無需重新編寫原來的類的情況下對這些功能進(jìn)行擴(kuò)展招狸。 通過繼承創(chuàng)建的新類稱為“子類”或“派生類”,被繼承的類稱為“基類”邻薯、“父類”或“超類”裙戏。繼承的過程,就是從一般到特殊的過程弛说。要實(shí)現(xiàn)繼承挽懦,可以通過“繼承”(Inheritance)和“組合”(Composition)來實(shí)現(xiàn)。繼承概念的實(shí)現(xiàn)方式有二類:實(shí)現(xiàn)繼承與接口繼承木人。實(shí)現(xiàn)繼承是指直接使用基類的屬性和方法而無需額外編碼的能力信柿;接口繼承是指僅使用屬性和方法的名稱冀偶、但是子類必須提供實(shí)現(xiàn)的能力;
2渔嚷、重寫(覆蓋)
在子類中出現(xiàn)和父類同名的方法进鸠,這個(gè)稱為重寫,重寫是行為的重新定義形病。重寫只能發(fā)生在有繼承關(guān)系的類之間客年,方法名稱相同即重寫,與參數(shù)沒有關(guān)系漠吻,重寫時(shí)訪問修飾符的可以訪問的范圍不能低于父類中訪問修飾符量瓜。對于private修飾的方法不能重寫。
如果途乃,子類重寫了父類方法绍傲,如何在子類中調(diào)用父類同名方法?
partent::方法名();
所以耍共,當(dāng)子類繼承父類時(shí)烫饼,需在子類的構(gòu)造中的第一步,首先調(diào)用父類構(gòu)造進(jìn)行復(fù)制试读。
function __construct($name,$sex,$school){
parent::__construct($name,$sex);
$this->school = $school;
}
3杠纵、實(shí)現(xiàn)繼承
給子類使用extends關(guān)鍵字,讓子類繼承父類钩骇;
class Student extends Person{}
4比藻、注意事項(xiàng)
1) PHP中繼承是單繼承,即extends后面只能有1個(gè)類名伊履;但是一個(gè)類進(jìn)行多層繼承韩容。
2)子類繼承父類的所有內(nèi)容,但父類中的private部分不能直接訪問唐瀑。
3)子類中新增加的屬性和方法是對父類的擴(kuò)展。
三插爹、多態(tài)
1哄辣、定義:
一個(gè)類被多個(gè)子類繼承,如果這個(gè)類的某個(gè)方法在多個(gè)子類中表現(xiàn)出不同的功能赠尾,我們稱這種行為為多態(tài)力穗。
多態(tài)是指OOP 能夠根據(jù)使用類的上下文來重新定義或改變類的性質(zhì)或行為,或者說接口的多種不同的實(shí)現(xiàn)方式即為多態(tài)气嫁。把不同的子類對象都當(dāng)作父類來看当窗,可以屏蔽不同子類對象之間的差異,寫出通用的代碼寸宵,做出通用的編程崖面,以適應(yīng)需求的不斷變化元咙。
2、實(shí)現(xiàn)多態(tài)必要途徑
1)子類繼承父類
2)重寫父類方法
3)父類引用指向子類對象巫员;
4)調(diào)重寫的方法
3庶香、案例
interface Computer {
public function version();
public function work();
}
class NotebookComputer implements Computer {
public function version() {
echo '聯(lián)想120';
}
public function work() {
echo '筆記本正在隨時(shí)攜帶運(yùn)行!';
}
}
class desktopComputer implements Computer {
public function version() {
echo 'IBM';
}
public function work() {
echo '臺(tái)式電腦正在工作站運(yùn)行简识!';
}
}
class Person {
public function run($type) {
$type->version();
$type->work();
}
}
$person = new Person();
$desktopcomputer = new desktopComputer();
$notebookcomputer = new NoteBookComputer();
$person->run($notebookcomputer);
四赶掖、其它
1、重載:
1)定義:
函數(shù)名一樣七扰,通過函數(shù)的參數(shù)個(gè)數(shù)或者參數(shù)類型不同奢赂,達(dá)到調(diào)用同一個(gè)函數(shù)名,但是可以區(qū)分不同的函數(shù)颈走。
2)注意
PHP面向?qū)ο笫遣恢С址椒ㄖ剌d的膳灶,但是可以通過魔術(shù)方法__call來實(shí)現(xiàn)重載的目的,但不推薦使用疫鹊。
3)案例
Class A {
public function test1($p) {
echo "接收一個(gè)參數(shù)<br/>";
}
public function test2($p) {
echo "接收兩個(gè)參數(shù)<br/>";
}
//提供__call 它一個(gè)對象調(diào)用某個(gè)方法袖瞻,而該方法不存在,則系統(tǒng)會(huì)自動(dòng)調(diào)用__call
function __call($method,$p) {
if ($method == "test") {
if (count($p) == 1) {
$this -> test1($p);
} elseif (count($p) == 2) {
$this -> test2($p);
}
}
}
}
$a = new A();
$a -> test(1);
$a -> test(21,43)
2拆吆、抽象:
1)定義
忽略一個(gè)主題中與當(dāng)前目標(biāo)無關(guān)的東西聋迎,專注注意與當(dāng)前目標(biāo)有關(guān)的方面。(就是把現(xiàn)實(shí)世界中的某一類東西枣耀,提取出來霉晕,用程序代碼表示,抽象出來的一般叫做類或者接口)捞奕。抽象并不打算了解全部問題牺堰,而是選擇其中的一部分,暫時(shí)不用管部分細(xì)節(jié)颅围。抽象包括兩個(gè)方面伟葫,一個(gè)數(shù)據(jù)抽象,二是過程抽象院促。
- 數(shù)據(jù)抽象 -->表示世界中一類事物的特征,就是對象的屬性.比如鳥有翅膀,羽毛等(類的屬性)
- 過程抽象 -->表示世界中一類事物的行為,就是對象的行為.比如鳥會(huì)飛,會(huì)叫(類的方法)
3筏养、面向?qū)ο笪宕蠡驹瓌t
1)單一職責(zé)原則SRP(Single Responsibility Principle)
是指一個(gè)類的功能要單一,不能包羅萬象常拓。如同一個(gè)人一樣渐溶,分配的工作不能太多,否則一天到晚雖然忙忙碌碌的弄抬,但效率卻高不起來茎辐。
2)開放封閉原則OCP(Open-Close Principle)
一個(gè)模塊在擴(kuò)展性方面應(yīng)該是開放的而在更改性方面應(yīng)該是封閉的。比如:一個(gè)網(wǎng)絡(luò)模塊,原來只服務(wù)端功能拖陆,而現(xiàn)在要加入客戶端功能弛槐,那么應(yīng)當(dāng)在不用修改服務(wù)端功能代碼的前提下,就能夠增加客戶端功能的實(shí)現(xiàn)代碼慕蔚,這要求在設(shè)計(jì)之初丐黄,就應(yīng)當(dāng)將服務(wù)端和客戶端分開,公共部分抽象出來孔飒。
3)替換原則(the Liskov Substitution Principle LSP)
子類應(yīng)當(dāng)可以替換父類并出現(xiàn)在父類能夠出現(xiàn)的任何地方灌闺。比如:公司搞年度晚會(huì),所有員工可以參加抽獎(jiǎng)坏瞄,那么不管是老員工還是新員工桂对,也不管是總部員工還是外派員工,都應(yīng)當(dāng)可以參加抽獎(jiǎng)鸠匀,否則這公司就不和諧了蕉斜。
4)依賴原則(the Dependency Inversion Principle DIP)
具體依賴抽象,上層依賴下層缀棍。假設(shè)B是較A低的模塊宅此,但B需要使用到A的功能,這個(gè)時(shí)候爬范,B不應(yīng)當(dāng)直接使用A中的具體類:而應(yīng)當(dāng)由B定義一抽象接口父腕,并由A來實(shí)現(xiàn)這個(gè)抽象接口,B只使用這個(gè)抽象接口:這樣就達(dá)到了依賴倒置的目的青瀑,B也解除了對A的依賴璧亮,反過來是A依賴于B定義的抽象接口。通過上層模塊難以避免依賴下層模塊斥难,假如B也直接依賴A的實(shí)現(xiàn)枝嘶,那么就可能造成循環(huán)依賴。一個(gè)常見的問題就是編譯A模塊時(shí)需要直接包含到B模塊的cpp文件哑诊,而編譯B時(shí)同樣要直接包含到A的cpp文件群扶。
5)接口分離原則(the Interface Segregation Principle ISP)
模塊間要通過抽象接口隔離開,而不是通過具體的類強(qiáng)耦合起來镀裤。
參考
https://blog.csdn.net/wang544831183/article/details/77322569
https://www.cnblogs.com/corvoh/p/5747856.html
http://www.runoob.com/php/php-oop.html