第十八章 物件導向的特性

水之原發表於2014-05-26

學習要點:
1.OOP 的封裝
2.OOP 的繼承
3.OOP 的多型

 

物件導向的三個主要特性是封裝、繼承和多型。

一.OOP的封裝

隱藏物件的欄位和實現細節,僅對外公開介面,控制在程式中欄位的讀和修改的訪問級
別;將抽象得到的資料和行為(或功能)相結合,形成一個有機的整體,也就是將資料與
運算元據的原始碼進行有機的結合,形成“類”,其中資料和函式都是類的成員。

 

欄位的作用域
1.public 公共的(類外可以訪問)
2.private 私有的(類內可以訪問)
3.protected 受保護的(類內和子類可以訪問,類外不可訪問)

 

建立使用了私有的欄位,這樣外部就無法訪問了

class Computer {
    //類的欄位(成員)
    private $_name = '聯想120';
    private $_model = 'LX';
}

 

通過一個公共方法作為入口,訪問私有欄位,而必須使用$this關鍵字。

class Computer {
    //類的欄位(成員)
    private $_name = '聯想120';
    private $_model = 'LX';
    //通過公共方法來訪問私有欄位
    function run() {
        echo $this->_name;
    }
}
$computer->run ();

 

屬性操作(私有欄位的賦值與取值)

可以設計兩個公共方法,一個方法為setName(),用於賦值;一個方法為getName(),
用於取值。

class Computer {
    //類的欄位(成員)
    private $_name;
    private $_model;
    //賦值
    function setName($_name) {
        $this->_name = $_name;
    }
    //取值
    function getName() {
        return $this->_name;
    }
}
$computer = new Computer ();
$computer->setName ( 'IBM' );
echo $computer->getName ();

如果有十個欄位那麼就必須要二十個方法才能夠賦值和取值,那麼有沒有更簡便的方法
呢?PHP內建兩個方法(攔截器)專門用於取值與賦值:__set(),__get()。

class Computer {
    //類的欄位(成員)
    private $_name;
    private $_model;
    //所有欄位的賦值都在這裡進行
    function __set($_key, $_value) {
        $this->$_key = $_value;
    }
    //所有欄位的取值都在這裡進行
    function __get($_key) {
        return $this->$_key;
    }
}
$computer = new Computer ();
$computer->_model = 'LX';
echo $computer->_model;

方法私有:有些使用類裡面的方法並不需要對外公開,只是裡面運作的一部分,這個時
候可以將方法也封裝起來。

class Computer {
    //類的欄位(成員)
    private $_name;
    private $_model;
    //私有方法
    private function getEcho() {
        echo '我是私有化的方法';
    }
    //公共方法一般是對外的入口
    public function run() {
        $this->getEcho ();
    }
}
$computer = new Computer ();
$computer->run ();

建議:方法前面如果沒有修飾符,那麼就是外部可訪問的公共方法,但為了讓程式更加
的清晰,建議在前面加上public。

 

常量(constant)
在類中可以定義常量,用來表示不會改變的值。對於從該類例項化的任何物件來說,常
量值在這些物件的整個生命週期中都保持不變。

class Computer {
    const PI = 3.1415926;
}
echo Computer::PI;

 

靜態類成員
有時候,可能需要建立供所有類例項共享的欄位和方法,這些欄位和方法與所有的類實
例有關,但不能由任何特定物件呼叫。

class Computer {
    public static $_count = 0;
}
echo Computer::$_count;

一般來說,必須將欄位做成私有化。所以可能需要這麼做:

class Computer {
    private static $_count = 0;
    public static function setRun() {
        self::$_count ++;
    }
    public static function getRun() {
        return self::$_count;
    }
}
Computer::setRun ();
echo Computer::getRun ();

 

Instanceof關鍵字
PHP5有一個instanceof關鍵字,使用這個關鍵字可以確定一個物件是類的例項、類的
子類,還是實現了某個特定介面,並進行相應的操作。

class Computer {
    
}
$computer = new Computer ();
echo ($computer instanceof Computer);

 

二.OOP繼承

繼承是從一個基類得到一個或多個類的機制。
繼承自另一個類的類被稱為該類的子類。這種關係通常用父類和孩子來比喻。子類將繼
承父類的特性。這些特性由屬性和方法組成。子類可以增加父類之外的新功能,因此子類也
被稱為父類的“擴充套件”。

在PHP中,類繼承通過extends關鍵字實現。繼承自其他類的類成為子類或派生類,子
類所繼承的類成為父類或基類。(PHP只支援單繼承,PHP不支援方法過載)。

class Computer {
    private $_name = '聯想120';
    private function __get($_key) {
        return $this->$_key;
    }
    public function run() {
        echo '我是父類';
    }
}
class NoteBookComputer extends Computer {
}
$notebookcomputer = new NoteBookComputer ();
$notebookcomputer->run ();
echo $notebookcomputer->_name;

 

欄位和方法的重寫(覆蓋)
有些時候,並不是特別需要父類的欄位和方法,那麼可以通過子類的重寫來修改父類的
欄位和方法。

class Computer {
    public $_name = '聯想120';
    protected function run() {
        echo '我是父類';
    }
}

class NoteBookComputer extends Computer {
    public $_name = 'IBM';
    public function run() {
        echo '我是子類';
    }
}

 

子類呼叫父類的欄位或方法
為了安全,我們一般將父類的方法封裝了起來,這樣,外部就無法呼叫,只能被繼承它
的子類所看到。這個時候,就需要通過子類操作來呼叫父類了。

class Computer {
    protected $_name = '聯想120';
    protected function run() {
        echo '我是父類';
    }
}

class NoteBookComputer extends Computer {
    public function getName() {
        echo $this->_name;
    }
    public function getRun() {
        echo $this->run ();
    }
}

 

通過重寫呼叫父類的方法
有的時候,我們需要通過重寫的方法裡能夠呼叫父類的方法內容,這個時候就必須使用
語法:父類名::方法() 或者parent::方法()即可呼叫。

class Computer {
    protected function run() {
        echo '我是父類';
    }
}

class NoteBookComputer extends Computer {
    public function run() {
        echo Computer::run ();
    }
}

 

final關鍵字可以防止類被繼承,有些時候只想做個獨立的類,不想被其他類繼承使用,
那麼就必須使用這個關鍵字。建議只要是單獨的類,都加上這個關鍵字。

final class Computer {
    //無法繼承的類
    final public function run() {
    } //無法被繼承的方法
}

class NoteBookComputer extends Computer {
    //會報錯
}

 

抽象類和方法(abstract)
抽象方法很特殊,只在父類中宣告,但在子類中實現。只有宣告為abstract的類可以聲
明抽象方法。

規則:
1.抽象類不能被例項化,只能被繼承。
2.抽象方法必須被子類方法重寫。

abstract class Computer {
    abstract function run();
}

final class NotebookComputer extends Computer {
    public function run() {
        echo '我實現了';
    }
}

 

介面(interface)
介面定義了實現某種服務的一般規範,宣告瞭所需的函式和常量,但不指定如何實現。
之所以不給出實現的細節,是因為不同的實體可能需要用不同的方式來實現公共的方法定
義。關鍵是要建立必須實現的一組一般原則,只要滿足了這些原則才能說實現了這個介面。

規則:
1.類全部為抽象方法(不需要宣告abstract)
2.介面抽象方法必須是public
3.成員(欄位)必須是常量

interface Computer {
    const NAME = '聯想120';
    public function run();
}

final class NotebookComputer implements Computer {
    public function run() {
        echo '實現了介面的方法';
    }
}
$notebookcomputer = new NoteBookComputer ();
$notebookcomputer->run ();
echo Computer::NAME;

 

子類可以實現多個介面

interface Computer {
    const NAME = '聯想120';
    public function run();
}

interface Notebook {
    public function book();
}

final class NotebookComputer implements Computer, Notebook {
    public function run() {
        echo '實現了介面的方法';
    }
    public function book() {
        echo '實現了介面的方法';
    }
}

 

三.多型

多型是指OOP 能夠根據使用類的上下文來重新定義或改變類的性質或行為,或者說接
口的多種不同的實現方式即為多型。把不同的子類物件都當作父類來看,可以遮蔽不同子類
物件之間的差異,寫出通用的程式碼,做出通用的程式設計,以適應需求的不斷變化。

interface Computer {
    public function version();
    public function work();
}

class NotebookComputer implements Computer {
    public function version() {
        
        echo '聯想120';
    }
    public function work() {
        echo '筆記本正在隨時攜帶執行!';
    }
}

class desktopComputer implements Computer {
    public function version() {
        echo 'IBM';
    }
    public function work() {
        echo '臺式電腦正在工作站執行!';
    }
}

class Person {
    public function run($type) {
        $type->version ();
        $type->work ();
    }
}

$person = new Person ();
$desktopcomputer = new desktopComputer ();
$notebookcomputer = new NoteBookComputer ();
$person->run ( $notebookcomputer );

 注:文章出自李炎恢PHP視訊教程,本文僅限交流使用,不得用於商業用途,否則後果自負。

相關文章