1. 程式人生 > >淺談多型以及php的實現方法

淺談多型以及php的實現方法

先簡單說一下多型
多型的三大特徵:

  • 子類繼承父類
  • 子類重寫父類
  • 父類指向子類

多型實現的前提:必須是類與類之間要有關係,要麼繼承,要麼實現,存在重寫(override),其實就是抽象函式或介面。
多型的應用:父類物件的引用指向子類物件,其實本質上就是一個向上轉型。
舉個模型例子,一家公司有員工類(Employee),還有其子類:銷售(Sales)、市場(Market)、工程師(Engineer)等。某一天老闆招待所有的員工開了個短會,完了之後對所有的員工(Employee)說,大家回去工作吧。在這裡我們可以認為老闆呼叫了所有員工物件的continueToWork()方法,而不是對一個個員工細說做什麼工作,比如對銷售部說你去制定銷售計劃(呼叫makeSalePlan();),對市場部說你去制定產品的價格(呼叫makeProductPrice();)….這種逐個細說的方式並不是面向物件,而是面向個體。可以確定的是,員工類應該有一個方法continueToWork()。而員工如何實現他們工作的方法卻只有精確到子類才能確定,因為不同的員工的工作方式是不一樣的。因此,我們很多時候只需要關心物件的父型別,而忽略更精確的子型別,比如上面老闆叫大家回去工作時,他對全體員工說的,主要指的是全體員工型別。
上述的UML圖:
這裡寫圖片描述

多型的好處:大大提高程式的擴充套件,增強系統的靈活性,降低模組間的耦合。
具體Java程式碼實現如下:

abstract class Employee{
    abstract void continueToWork();
}
class Sales extends Employee{
    private void makeSalePlan(){
        System.out.println("make sale plan");
    }

    public void continueToWork(){
        makeSalePlan();
    }
}

class
Market extends Employee{
private void makeProductPrice(){ System.out.println("make product price"); } public void continueToWork(){ makeProductPrice(); } } class Engineer extends Employee{ private void makeNewProduct(){ System.out.println("make new product"
); } public void continueToWork(){ makeNewProduct(); } }

錯誤的呼叫示範:

class Demo{
    public static void main(String[] args){
        Sales s = new Sales();
        s.continueToWork();
        Market m = new Market();
        m.continueToWork();
        Engineer e = new Engineer();
        e.continueToWork();
    }
}

以上的這種呼叫並不能稱為多型,雖然看起來都通過呼叫continueToWork()來得到結果,但是並不是通過同一介面來實現的,這只是不同類的物件都有相同名稱的介面方法,用上述模型來說,就是老闆單獨對銷售部說你去工作,單獨對市場部說你去工作,單獨對工程師說你去工作,而不是對所有的員工說。

正確的呼叫方式:

class Demo{
    public static void main(String[] args){
        Work(new Sales());//Employee e = new Sales();
        Work(new Market());//Employee e = new Market();
        Work(new Engineer());//Employee e = new Engineer();
    }
    public static void Work(Employee e){
        e.continueToWork();
    }
}

上面通過呼叫統一的介面Work()來工作,這種呼叫才是多型。

還可以利用過載來實現偽多型:(注:本作者認為過載不屬於多型的範疇,但是過載這種語言特性是可以幫助我們來實現偽多型的,具體請見本人的另一篇博文:《過載不應歸在多型的範疇內》

class Demo{
    public static void main(String[] args){
        Work(new Sales());
        Work(new Market());
        Work(new Engineer());
    }
    public static void Work(Sales s){
        s.continueToWork();
    }
    public static void Work(Market m){
        m.continueToWork();
    }
    public static void Work(Engineer e){
        e.continueToWork();
    }
}

為什麼我稱上面呼叫是偽多型呢?因為上述的這種方式,細究其實跟第一種錯誤呼叫方式是一樣的,只不過利用了過載加以封裝,使得看起來是通過統一的介面Work()來工作,但其實它並沒有讓父類物件的引用指向子類物件。

最後附上php程式碼實現多型:

<?php
abstract class Employee{
    abstract function continueToWork();
}
class Sales extends Employee{
    private function makeSalePlan(){
        echo "make sale plan";
    }

    public function continueToWork(){
        $this->makeSalePlan();
    }
}

class Market extends Employee{
    private function makeProductPrice(){
        echo "make product price";
    }

    public function continueToWork(){
        $this->makeProductPrice();
    }
}

class Engineer extends Employee{
    private function makeNewProduct(){
        echo "make new product";
    }

    public function continueToWork(){
        $this->makeNewProduct();
    }
}

class Demo{
    public function Work($employeeObj){
        $employeeObj->continueToWork();
    }
}
//呼叫
$obj = new Demo();
$obj->Work(new Sales());
$obj->Work(new Market());
$obj->Work(new Engineer());
?>