多态的定义:对于接口的多种不同实现方式。
例如,程序中定义一个数据存储的 set()
接口,我们分别用 MySQL 和 Redis 实现了 set()
的不同内部逻辑,这两种实现方式就实现了 多态 的概念。
PHP 和 Go 实现多态的方式不同,PHP 作为动态类型的语言实现起来更加“松散”,Go 作为静态类型的语言则更加严格,当然其中还有语言本身的特性。
PHP 的实现
在我使用 PHP 的编程中,接口 interface 的使用频率屈指可数。原因是 PHP 作为动态类型的语言,本身就不需要声明变量类型,而这也是 PHP 能够快速开发 web 应用的核心之一。
接下来我们用程序设计多态的实现,假定一个实现面积计算的接口
interface Area
{
public function get();
}
然后是两个实现:矩形和三角形
// 矩形
class Rectangle implements Area {
public function getArea($a, $b)
{
return $a * $b;
}
}
// 三角形
class Triangle implements Area {
public function getArea($a, $b)
{
return $a * $b / 2;
}
}
然后在使用时,就可以使用 interface 作为参数约束了
function myArea(Area $area, $a, $b)
{
return $area->getArea($a, $b);
}
但是因为 PHP 是动态类型的语言,不需要对参数的类型约束,完全可以用以上方式写代码,然后 interface 的定义就略显累赘,当然在框架设计中还是可以看到 interface 的使用场景,interface 确实明确的定义了实现的行为。但是开发中我不太会用 interface, 就算需要时也是用继承来实现,在 PHP 中继承完美覆盖了 interface 的作用,既可以约束子类实现的相同行为,还可以定义默认行为和扩展。
function myArea($area, $a, $b)
{
return $area->getArea($a, $b);
}
Go 的实现
Go 作为静态类型的语言,需要强制对变量的类型声明,这里再用 Go 实现一次上述简单的功能,首先定义接口:
type area interface {
Get(int, int) int
}
然后定义矩形和三角形的实现:
// 矩形
type Rectangle struct {}
func (Rectangle) Get(a int, b int) int {
return a * b
}
// 三角形
type Triangle struct {}
func (Triangle) Get(a int, b int) int {
return a * b / 2
}
// 多态的调用
func myArea(ar area, a int, b int) int {
return ar.Get(a, b)
}
总结
Go 的 interface 在项目中随处可见,而 PHP 开发中很少见。以上程序还存在一个问题,变量 a,b
义在两个实现中含义是不同的,这时扩展梯形时两个变量就会出现问题,需要将 a, b
放到 struct 结构体中,而 PHP 则是放在构造函数中。