后来我终于知道 , 它并不是我的花 ,我只是恰好途径了它的盛放。
说明
封装是类的构建过程,php具有;php也具有继承的特性。唯独这个多态,php体现的十分模糊。原因是php是弱类型语言。
java的多态体现的十分清晰,大体分两类:父类引用指向子类对象;接口引用指向实现接口的类对象。java声明变量时都要给变量设定类型,所以存在什么父类引用和接口引用。而php则没有这点体现,php声明变量不需要给变量设定类型,一个变量可以指向不同的数据类型。所以,php不具有像java一样的多态。
多态,作为面向对象编程中的一种设计模式,指的是通过遵循同一个interface,类可以有不同的功能实现(相当于说,有多种形态)。
在编程世界里,多态形式可以让我们的程序更加地模块化,易于扩展,而不是到处都是基于不同状态的条件判断,比如动不动就switch,动不动就层层嵌套if判断,这种情况下,十有八九是你的代码“有问题”了。
Interfaces
interface里可以定义方法名及相应参数,任何实现这个interface的类必须具体实现interface里定义的所有抽象方法,一个class可以实现多个interface
1 2 3 4 5
| interface MyInterface { public function doThis(); public function doThat(); public function setName($name); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class MyClass implements MyInterface { protected $name; public function doThis() { } public function doThat() { } public function setName($name) { $this->name = $name; } }
class MyClass implements MyInterface { private function doThat() { } public function setName() { } }
|
Abstract
Abstract Class可以说是介于interface和普通class之间,它既可以通过abstract method的形式定义统一的接口,又可以定义具体的功能实现。一个扩展了该Abstract Class的普通class,必须得具体实现该Abstract Class的所有抽象方法。
1 2 3 4 5 6 7 8
| abstract class MyAbstract { public $name; public function doThis() { } abstract public function doThat(); abstract public function setName($name); }
|
问题的引出
假设你有一个articleclass:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Article { public $title; public $author; public $date; public $category; public function __construct($title, $author, $date, $category = 0) { $this->title = $title; $this->author = $author; $this->date = $date; $this->category = $category; } }
|
现在呢,你想添加一个方法,来以不同的形式输出article相关的信息,比如说XML格式,或者说JSON格式。
可能你一开始会想着这么来处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Article { public function write($type) { $ret = ''; switch($type) { case 'XML': $ret = '<article>'; $ret .= '<title>' . $obj->title . '</title>'; $ret .= '<author>' . $obj->author . '</author>'; $ret .= '<date>' . $obj->date . '</date>'; $ret .= '<category>' . $obj->category . '</category>'; $ret .= '</article>'; break; case 'JSON': $array = array('article' => $obj); $ret = json_encode($array); break; } return $ret; } }
|
虽然功能上能实现效果,但是看上去很糟糕,不是吗?假设,将来你又想加上其他的格式,那该怎么办?再加几个case判断,这代码得多臃肿呢?
关于面向对象,有一个很重要的原则就是,一个class应该只做份内之事。每当你遇到大块的条件判断的时候,你就应该有所警醒,因为很可能这个时候你已经在同一个class或method下,硬要去做太多的事情了。那么这个时候,也就是该尝试多态实现了。
尝试解决
定义 Interface
1 2 3
| interface Writer { public function write(Article $obj); }
|
具体实现 Interface
XMLWriter可以这样来实现:
1 2 3 4 5 6 7 8 9 10 11
| class XMLWriter implements Writer { public function write(Article $obj) { $ret = '<article>'; $ret .= '<title>' . $obj->title . '</title>'; $ret .= '<author>' . $obj->author . '</author>'; $ret .= '<date>' . $obj->date . '</date>'; $ret .= '<category>' . $obj->category . '</category>'; $ret .= '</article>'; return $ret; } }
|
JSONWriter:
1 2 3 4 5 6
| class JSONWriter implements Writer { public function write(Article $obj) { $array = array('article' => $obj); return json_encode($array); } }
|
这样每一种个的class只负责各自的那一件事。
具体调用
1 2 3 4 5 6
| class Article { public function write(Writer $writer) { return $writer->write($this); } }
|
这样article的write方法接收的是一个实现了Writer这个interface的具体类,article不再需要关注具体该用什么样的格式,那已经不是它要负责的了,交给背后具体的Writer去处理就好了。
http://pilishen.com/posts/Understanding-and-Applying-Polymorphism-in-PHP