浅谈多态以及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(Employee $employeeObj){//添加父类类型限制传参类型,使其满足多态第三点要求,父类指向子类
		$employeeObj->continueToWork();
	}
}
//调用
$obj = new Demo();
$obj->Work(new Sales());
$obj->Work(new Market());
$obj->Work(new Engineer());
?>

参考资料:
CSDN帖子:重载是不是多态?重载是不是面向对象?
Qi_Yuan的博文《java之多态的使用》


感谢wonderwiller618对本文错误的纠正

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值