编程设计:PHP 5中多态性的实现方案浅析

作者:朱先忠编译
  提要:本文将讨论多态性的概念及其在面向对象设计中的应用,还将分析如何在PHP 5中使用多态性以及存在的优缺点。

  PHP的最新发行版本中已经实现了对迟绑定的支持。当然,在使用其迟绑定功能时还存在很多问题。如果你使用的是更旧版本的PHP(我的服务器上运行的是PHP 5.0.1版本),那么你可能发现其中缺乏对于迟绑定的支持。因此,请注意本文中的代码有可能无法工作在你特定的PHP 5版本中。

  一、 PHP 5和多态性

  本文想讨论面向对象编程中最为重要的部分之一--多态性的设计。为了说明问题,我使用了PHP 5。在你继续阅读之前,请首先明确本文并不是完全有关于PHP的。尽管这种语言在以前的两个主要版本中在快速开发方面已经取得很大的进步,但是,在其与更为成熟的语言如C++或者Java相匹敌之前,它对于对象的支持还要经历一段历程。

  如果你是一位面向对象编程的入门者,那么本文可能不适合你,因为多态性这部分知识比较特别:一旦理解了它,你将永远不会忘记。如果你想简单了解一点对象编程和设计知识,并且当某人说"某个对象是多态的"时,还不十分清楚这是什么意思的话,那么本文正适合你。
到本文最后,你应该知道什么是多态性以及如何把它应用到面向对象的设计中,并且你会了解PHP 5中对象编程的优点与不足。

  二、什么是多态性?

  多态性,其来自于dictionary.com的定义是"以不同形式,阶段或者类型出现在独立的组织中或者同种组织中,而不存在根本区别。"由该定义,我们可以认为,多态性是一种通过多种状态或阶段来描述相同对象的编程方式。其实,它的真正意义在于:实际开发中,我们只需要关注一个接口或基类的编程,而不必担心一个对象所属于的具体类(class)。

  如果你熟悉设计模式,即使只是有个初步了解,那么你也会了解这个概念。事实上,多态性可能是基于模式设计编程中的最伟大的工具。它允许我们以一种逻辑的方式来组织相类似的对象从而实现在具体编码时不必担心对象的具体类型;而且,我们只需要对一个所期望的接口或基类编程即可。一个应用程序越抽象,则它就显得越灵活--而多态性是对行为加以抽象的最好的方式之一。

  例如,让我们考虑一个叫Person的类。我们可以用称为David,Charles和Alejandro的类来子类化Person。Person有一个抽象方法AcceptFeedback(),所有的子类都要实现这个方法。这意味着,任何使用基类Person的子类的代码都能调用方法AcceptFeedback()。你不必检查该对象是一个David还是一个Alejandro,仅知道它是一个Person就够了。结果是,你的代码只需关注"最小公分母"-Person类即可。

  在这个示例中的Person类也可以被创建为一个接口。当然,与上面相比存在一些区别,主要在于:一个接口并没有给出任何行为,而仅确定了一组规则。一个Person接口要求的是"你必须支持AddFeedback()方法",而一个Person类可以提供一些AddFeedback()方法的缺省代码-你对之的理解可以是"如果你不选择支持AddFeedback(),那么你应该提供一种缺省实现。"至于如何选择接口或基类则并非本文的主题;但是,一般说来,你需要通过基类来实现一个缺省的方法。如果你能够简单地勾勒出你的类所要实现的一组期望的功能,那么你也可以使用一个接口。

  三、应用多态性设计

  我们将继续使用Person基类的例子,现在让我们分析一个非多态性的实现。下列示例中使用了不同类型的Person对象--这是一种非常不理想的编程方式。注意,实际的Person类被省略。目前为止,我们仅关心代码调用的问题。

<?php
 $name = $_SESSION['name'];
 $myPerson = Person::GetPerson($name);
 switch (get_class($myPerson)){
  case 'David' :
   $myPerson->AddFeedback('Great Article!','Some Reader', date('Y-m-d'));
   break;
  case 'Charles':
   $myPerson->feedback[] = array('Some Reader', 'Great Editing!');
   break;
  case 'Alejandro' :
   $myPerson->Feedback->Append('Awesome Javascript!');
   break;
  default :
   $myPerson->AddFeedback('Yay!');
 }
?>

  这个示例展示了行为不同的对象,还有一个switch语句用于区分不同的Person类对象,从而执行其各自相应的正确操作。注意,这里针对不同条件的回馈注释是不同的。在实际应用程序开发中可能不会出现这种情形;我仅为了简单地说明类实现中存在的区别。

  下面的一个示例使用了多态性。

<?php
 $name = $_SESSION['name'];
 $myPerson = Person::GetPerson($name);
 $myPerson->AddFeedback('Great Article!', 'SomeReader', date('Y-m-d'));
?>

  注意,这里没有switch语句,而最重要的是,缺乏有关Person::GetPerson()会返回什么类型的对象。而另一个Person::AddFeedback()是一个多态方法。行为完全是由具体类进行封装的。请记住,在此无论我们使用的是David,Charles还是Alejandro,调用代码从不必了解具体类的功能,而仅知道基类就可以了。

  尽管我的示例并不完美,但是,从调用代码的角度,它已经展示了多态性的基本用法。现在我们需要分析这些类的内部实现。从一个基类进行派生的一个最伟大的地方在于,该派生类能够存取父类的行为,这种情况常常是缺省的实现,但是也可能出现在类继承链中用于创建更为复杂的行为。下面是这种情况的一个简单展示。

<?php
class Person{
 function AddFeedback($comment, $sender, $date){
  //把回馈添加到数据库
 }
}
class David extends Person{
 function AddFeedback($comment, $sender){
  parent::AddFeedback($comment, $sender,
  date('Y-m-d'));
 }
}
?>

  在此,David类中的AddFeedback方法实现中首先调用了Person::AddFeedback方法。你可能注意到,它模仿了C++,Java或C#中的方法重载。请记住,这仅是一个简单化的示例,并且你编写的实际代码完全依赖于你的实际工程。

四、PHP 5中的迟绑定

  依我的看法,迟绑定正是使得Java和C#如此引人注目的重要原因。它们允许基类方法用"this"或$this来调用方法(即使它们不存在于基类中或调用一个基类中的方法,它有可能为继承类中的另一个版本所代替)。你可以认为如下的实现在PHP中是允许的:

<?php
class Person{
 function AddFeedback($messageArray) {
  $this->ParseFeedback($messageArray);
  //写向数据库
 }
}
class David extends Person{
 function ParseFeedback($messageArray){
  // 进行一些分析
 }
}
?>

  记住,在Person类中并没有ParseFeedback。现在,假定你拥有这一部分实现代码(为了本例说明问题起见),那么这会导致$myPerson成为一个David对象:

<?php
$myPerson = Person::GetPerson($name);
$myPerson->AddFeedback($messageArray);
?>

  出现分析错误!大致错误信息为,方法ParseFeedback并不存在或者一些类似的信息。关于PHP 5中的迟绑定我们就讨论这些!下面我们再归纳一下迟绑定的概念。

  迟绑定意味着,方法调用在最后时刻才绑定到目标对象。这意味着,当该方法被运行时刻调用时,那些对象已经有了一种具体类型。在我们上面的示例中,你调用了David::AddFeedback(),而既然David::AddFeedback()中的$this引用一个David对象,那么你可以逻辑地假定ParseFeedback()方法是存在的--但事实上它并不存在,因为AddFeedback()是在Person中定义的,并且从Person类中调用ParseFeedback()。
不幸的是,没有简单的方法来消除PHP 5中的这种行为。这意味着,当你想创建一个灵活的多态类层次时你可能有点无能为力。

  我必须指出,我选择PHP 5作为本文的表达语言仅仅是因为:这种语言并没有实现对象概念的完美抽象!因为PHP 5还处于其测试版本运行期,所以这是可以谅解的。另外,既然该语言中加入了抽象类和接口,迟绑定也应该被实现。

  五、小结

  至此,你应该基本了解什么是多态性以及为什么PHP 5在实现多态性方面并不完美。一般说来,你应该知道如何用一个多态性对象模型来封装有条件的行为。当然,这样会提高你的对象的灵活性,并且意味着更少的代码实现。另外,通过封装满足一定条件的行为(具体要依赖于对象的状态),你还提高了代码的清晰程度。

时间: 2024-08-17 22:39:45

编程设计:PHP 5中多态性的实现方案浅析的相关文章

PHP 5.0中多态性的实现方案浅析

    提要:本文将讨论多态性的概念及其在面向对象设计中的应用,还将分析如何在PHP 5中使用多态性以及存在的优缺点. PHP的最新发行版本中已经实现了对迟绑定的支持.当然,在使用其迟绑定功能时还存在很多问题.如果你使用的是更旧版本的PHP(我的服务器上运行的是PHP 5.0.1版本),那么你可能发现其中缺乏对于迟绑定的支持.因此,请注意本文中的代码有可能无法工作在你特定的PHP 5版本中. 一. PHP 5和多态性 本文想讨论面向对象编程中最为重要的部分之一--多态性的设计.为了说明问题,我使

PHP 5.0中多态性的实现方案

PHP的最新发行版本中已经实现了对迟绑定的支持.当然,在使用其迟绑定功能时还存在很多问题.如果你使用的是更旧版本的PHP(我的服务器上运行的是PHP 5.0.1版本),那么你可能发现其中缺乏对于迟绑定的支持.因此,请注意本文中的代码有可能无法工作在你特定的PHP 5版本中. 一. PHP 5和多态性 本文想讨论面向对象编程中最为重要的部分之一--多态性的设计.为了说明问题,我使用了PHP 5.在你继续阅读之前,请首先明确本文并不是完全有关于PHP的.尽管这种语言在以前的两个主要版本中在快速开发方

函数式编程在Redux/React中的应用

本文简述了软件复杂度问题及应对策略:抽象和组合;展示了抽象和组合在函数式编程中的应用;并展示了Redux/React在解决前端状态管理的复杂度方面对上述理论的实践.这其中包括了一段有趣的Redux推导. 软件复杂度及其应对策略 软件复杂度 软件的首要技术使命是管理复杂度.--代码大全 在软件开发过程中,随着需求的变化和系统规模的增大,我们的项目不可避免地会趋于复杂.如何对软件复杂度及其增长速率进行有效控制,便成为一个日益突出的问题.下面介绍两种控制复杂度的有效策略. 对应策略 抽象 世界的复杂.

游戏编程设计,c语言的问题

问题描述 游戏编程设计,c语言的问题 在vc++中想用conio.h文件,但是没有,有人推荐下载一个conio库,下载后怎么加入vc中呢?求大神们帮帮忙 解决方案 把所有相关的.h文件放到include文件夹里面,把所有的.lib文件放到lib文件夹里面.把所有的dll文件放到系统文件夹里面,就是C盘的system32(32位系统),或者system64(64位系统) 解决方案二: 第一种方案如楼上所说~第二种是把这个库函数放在你需要编写主程序的同一文件夹中~ 解决方案三: C语言的模块化设计和

ADP 0.74发布 Web数据库编程设计

ADP是一种编程语言,用于Web数据库编程设计.它是一种脚本语言和轻型的编程语言,可以很容易安装和轻松地混合使用SQL. ADP 0.74版本修复了导入Access数据库中的错误. 下载地址: adp_bin_OBS600D.tar.gz&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;          330.5 KB adp_bin_centos55_x64.tar.gz     350.9 KB adp_bi

access 如何编程打开其他数据库中的窗体?

access|编程|数据|数据库 如何编程打开其他数据库中的窗体?    简述:如何编程打开其他数据库中的窗体?    问题: 如何编程打开其他数据库中的窗体,使用完毕后退回?我新建了一个数据库,里面只有一个Form,我想在Form上添加几个按钮,每个按钮上对应一个Click事件,事件的动作就是打相应的Access数据库,并执行该数据库中的Menu表单,关闭数据库后又回到有按钮的Form来.   回答: Function OpenOhterMDB()    Dim objApp As New A

网页布局设计:使用数学中的模数精确布局

在设计中可以使用许多数学公式,比如常用的黄金分割比就是其中之一.在网页设计布局中,我们也能通过精密的计算来获得理想的排版比例,本文将介绍使用数学中的"模数"来计算网页布局大小,从而获得更为合理的布局. 在IT工业中,内置标准.国际标准.国家标准才是真正意义的规范.而在应用领域(包括web应用的开发)的开发中,标准是各自为政乱七八糟的,微软如果不考虑市场和经济利益也不是不吊这些标准的.我不得不汗一个. 二.模数网页设计中的应用 好了,鄙视完小儿科的网页设计,我们来谈谈"模数&q

access编程打开其他数据库中的窗体

简述:如何编程打开其他数据库中的窗体? 问题: 如何编程打开其他数据库中的窗体,使用完毕后退回? 我新建了一个数据库,里面只有一个Form,我想在Form上添加几个按钮,每个按钮上对应一个Click事件,事件的动作就是打相应的Access数据库,并执行该数据库中的Menu表单,关闭数据库后又回到有按钮的Form来. 回答: function openohtermdb() dim objapp as new access.application objapp.opencurrentdatabase

Android编程实现擦除Bitmap中某一块的方法

  Android编程实现擦除Bitmap中某一块的方法         以前要截取Bitmap中的图片使用的一块块的拼接,虽然可以实现,但是效率很低.想了很久,无意中看到网上的对BITMAP图片的RGB信息进行修改,然后想出了这个办法,感觉用起来还是挺舒服.很多出错处理都没有写,只实现基本功能啊 public static Bitmap setTransparentAreaForBitmap(Bitmap b, int width, int height, int paddingleft, i