關於抽象類和介面的初步理解
什麼是抽象類
-
抽象類是指在 class 前加了 abstract 關鍵字且存在抽象方法(在類方法 function 關鍵字前加了 abstract 關鍵字)的類。
-
抽象類不能被直接例項化。抽象類中只定義(或部分實現)子類需要的方法。子類可以通過繼承抽象類並通過實現抽象類中的所有抽象方法,使抽象類具體化。
-
如果子類需要例項化,前提是它實現了抽象類中的所有抽象方法。如果子類沒有全部實現抽象類中的所有抽象方法,那麼該子類也是一個抽象類,必須在 class 前面加上 abstract 關鍵字,並且不能被例項化。
引用連結
-
介面(Interface)—— 定義行為
-
抽象類(Abstract Class) —— 實現行為
-
具體類(class)——執行行為
引用連結
-
抽象類就是一個類的服務提供商,擁有眾多服務,你不用必須用,當需要的時候你來用就可以,如果你覺得不提供服務不滿意,你還可以自己來做。
-
抽象方法是必須實現的方法。就象動物都要呼吸。但是魚用鰓呼吸,豬用肺呼吸。
動物類要有呼吸方法。怎麼呼吸就是子類的事了。
為什麼要使用抽象類
按照我目前的知識理解:
-
保持程式的一致性
-
抽象類限制了實現的方法,也是為了保持一致性
-
增加程式碼重用性,例如一些公共類不需要實現,只需要呼叫裡面的方法就可以了。
-
現在有很多討論和建議提倡用interface代替abstract類,兩者從理論上可以做一般性的混用,但是在實際應用中,他們還是有一定區別的。抽象類一般作為公共的父類為子類的擴充套件提供基礎,這裡的擴充套件包括了屬性上和行為上的。而介面一般來說不考慮屬性,只考慮方法,使得子類可以自由的填補或者擴充套件介面所定義的方法,就像JAVA王子所說的事件中的介面卡就是一個很好的應用。
用一個簡單的例子,比如說一個教師,我們把它作為一個抽象類,有自己的屬性,比如說年齡,教育程度,教師編號等等,而教師也是分很多種類的,我們就可以繼承教師類而擴充套件特有的種類屬性,而普遍屬性已經直接繼承了下來。
而介面呢~還是拿教師做例子,教師的行為很多,除了和普通人相同的以外,還有職業相關的行為,比如改考卷,講課等等,我們把這些行為定義成無body的方 法,作為一個集合,它是一個interface。而教師張三李四的各自行為特點又有不同,那麼他們就可以擴充套件自己的行為body。從這點意義上來說,interface偏重於行為。
怎樣使用抽象類
<?php
abstract class Shape{ //這是一個抽象類,不能例項化
protected $color; //抽象類裡面一般都是使用protected來保護屬性,這是封裝的意義
public function __construct($color = `red`) { //抽象類可以使用構造方法,主要是為了方便程式碼重用,構造方法裡面也可以使用預設引數,當沒有配置引數的時候,就會使用預設的引數,寫法如上
$this->color = $color;
}
public function getColor() { //只是為了演示需要的一個方法
return $this->color;
}
abstract public function getArea(); //構造方法是為了限制程式碼,對於繼承這個構造類的子類,必須限制擁有這個構造方法,主要為了保持程式碼一致性。
}
class Square extends Shape{
protected $length = 4;
public function getArea() {
return pow($this->$length, 2);
}
}
class Circle extends Shape{ //這裡因為沒有構造方法getArea,所以程式碼允許會報錯的。
}
$shape = new Square();
var_dump($shape);
?>
介面和抽象類
-
抽象類不能被直接例項化,抽象類中只定義子類需要的方法,子類可以繼承並且通過實現其中的抽象方法,使抽象類具體化。例如一個名為media的類,他是用於描述各種公開出版的共同性質,因為media不表示真實的實體,而是一些相似實體的泛化表示,所以不例項化,這樣就需要宣告為抽象類,然後再由各種的派生的Media類繼承此抽象類
-
抽象類的每個子類都必須實現抽象類中的所有抽象方法,或者把他們自身也宣告為抽象方法。
-
擴充套件類不僅僅負責簡單實現抽象類的方法,還必須重新宣告方法,新的方法不能比抽象方法的訪問控制更嚴格,新的實現方法的引數個數應該和抽象方法的引數個數一樣。
-
介面定義了實現某種服務的一般規範,宣告瞭必須的函式和常量,但是不指定如何實現。關鍵是要建立必須實現的一組一般原則,只有滿足了這些原則才能說實現了這個介面。
-
抽象類提供了具體實現的標準,而介面則是純粹的模板。介面只能定義功能而不包含實現的內容。
-
任何實現介面的類都要實現介面中所定義的所有方法,否則類必須宣告為abstract。
-
實現介面的類接受他的繼承的類以及實現的介面的型別。
什麼時候用介面,什麼時候用抽象類
-
如果要建立一個模型,這個模型將由一些緊密相關的物件引用,就可以採用抽象類,如果要建立將由一些不想關的物件採用的功能,應該用介面。
-
如果必須從多個來源繼承行為,就是用介面。
-
如果知道所有類都會共享一個公共的行為實現,就使用抽象類,並在其中實現行為。介面無法實現。
-
一個類只能extends一個父類,但可以貫徹多個介面。
介面作用一:
介面類就是一個類的領導者,指明方向,子類必須完成它指定方法。
當有很多人一起開發一個專案時,可能都會去呼叫別人寫的一些類,那你就會問,我怎麼知道他的某個功能的實現方法是怎麼命名的呢,這個時候php介面類就起到作用了,當我們定義了一個介面類時,它裡面的方式是下面的子類必須實現的,比如
interface Shop
{
public function buy($gid);
public function sell($gid);
public function view($gid);
}
class BaseShop implements Shop
{
public function buy($gid)
{
echo `你購買了ID為 :` . $gid . `的商品`;
}
public function sell($gid)
{
echo `你購賣ID為 :` . $gid . `的商品`;
}
public function view($gid)
{
echo `你瀏覽了ID為 :` . $gid . `的商品`;
}
}
介面作用二:
有時候,我們需要設計一個物品,比如shape,這個shape有不同的形狀,有不同的顏色,可作不同的運動,等等。當然我們可以把這些都放在一個類裡面,但這樣,如前面說的,只是過程程式設計,不是OO程式設計。你會說,像上面例子一樣,做一個抽象類,然後在子類裡實現所有的功能。好象不錯,進步了。這樣子類裡面要實現形狀,顏色,運動等功能,OK嗎?記住,OO裡面還有一條原則,為了最大程度的做到程式碼重用,一個類裡最好只實現一個功能,也就是說,一個類做形狀,一個類做顏色,一個類做運動 。這樣如果其他的類要用到顏色的功能時,我們就可以重用這個顏色類,同理,這樣我們可以很容易的重用運動類,形狀類,等等。
但這樣問題出來了,現在我們要用到上面所有的功能,但又分散在三個類裡面,怎麼辦?這時我們就要用到抽象類和介面了。選定一個跟shape關聯最大的一項–形狀,把它做成抽象類, 其他兩樣,把它們做成介面,然後在子類裡面extends一個抽象類,再implements兩個介面就行了。如:
class Square extends Shape implements 顏色, 運動, ... {
...
}
抽象類作用一:
抽象類就是一個類的服務提供商,擁有眾多服務,你不用必須用,當需要的時候你來用就可以,如果你覺得不提供服務不滿意,你還可以自己來做。
這裡是一個例子,想上面一樣我定義了一個商店類,抽所了它所有像的部分,買(buy),賣(sell),看(view),並且抽象類裡都實現了這些方法,那麼繼承它的子類就自動獲得了這些方法,子類就做它自己獨特的東西,減少程式碼的重複,提高複用性。
abstract class BaseShop
{
public function buy($gid)
{
echo `你購買了ID為 :` . $gid . `的商品`;
}
public function sell($gid)
{
echo `你購賣ID為 :` . $gid . `的商品`;
}
public function view($gid)
{
echo `你瀏覽了ID為 :` . $gid . `的商品`;
}
}
class BallShop extends BaseShop
{
var $itme_id = null;
public function __construct()
{
$this->itme_id = 2314;
}
public function open()
{
$this->sell($this->itme_id);
}
}
抽象類作用二:
在抽象類裡面設定抽象方法
在oo設計時,會把一些通用的方法放在一個類裡,但考慮到子類繼承時的差異性,又不能把它事先實現,就只好用到這個抽象類或介面了。這裡很清楚的顯示了在抽象類裡,我們貫徹了設原用到點setCenter()的方法,這樣,當子類繼承它時,就不用再重複寫這個設原點的方法了。那麼為什麼draw的方法要設定成抽象方法呢?這是因為不同的子類要用不同的實現方法。
abstract class Shape
{
function setCenter($x, $y)
{
$this->x = $x;
$this->y = $y;
}
abstract function draw();
protected $x, $y;
}
參考:http://chengxudaren.com/index.php?act=article&op=detail&a_id=152