当你学习OOP面向对象的时候也许经常会接触到“多态”这个概念,但是总是学了又忘忘了又学,其实多态是面向对象中是一个很基础的概念,它是许多设计模式的组成部分,今天我们来通过一个实例重温和回顾下什么是多态。
多态的定义
多态(Polymorphism )描述了类有不同的功能,但是他们共享同一个接口,这就是多态的定义。
一个例子
看一个例子:
假设我们一个一个文章类来管理文章
class Base_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;
}
}
这时候,我们想添加一个方法来输出不同格式的信息,比如 “xml” 比如“json”,
这时你也许会想这么做:
class Base_Article {
//...
public function write($type) {
$ret = '';
switch($type) {
case 'XML':
$ret = '
';
$ret .= '';
$ret .= '' . $this->author . '';
$ret .= '' . $this->date . '';
$ret .= '';
$ret .= '
';
break;
case 'JSON':
$array = array('article' => $this);
$ret = json_encode($array);
break;
}
return $ret;
}
}
这种解决方案目前看起来没什么大问题,但是如果我们以后想添加更多的格式,就必须要修改这个方法,往里面添加更多的 case
,代码开始变的丑陋。
OOP 的一个重要原则就是一个类应该做一件事,并且把它做好
这时候我们就用到多态了,我们可以将格式输出的代码放到独立的类中,并通过 PHP 的接口 interface 来约定不同类使用相同的方法。
格式接口类
interface Writer {
public function write(Base_Article $obj);
}
JSON 格式类
class JSONWriter implements Writer{
public function write(Base_Article $obj) {
$array = array('article' => $obj);
return json_encode($array);
}
}
XML 格式的类
class XMLWriter implements Writer{
public function write(Base_Article $obj) {
$ret = '
';
$ret .= '';
$ret .= '' . $obj->author . '';
$ret .= '' . $obj->date . '';
$ret .= '';
$ret .= '
';
return $ret;
}
}
现在有各自的类处理特定的格式,这些类通过继承Writer
接口提供了统一的方法,
现在修改下 Base_Article
类,原来write
方法里的格式化代码类已经被剥离到一个个的格式化类里了,现在要做的就是调用这些类:
class Base_Article {
//...
public function write(Writer $writer) {
return $writer->write($this);
}
}
现在你可能会疑惑,我应该实例化哪个格式类,可以有很多策略。例如我们根据用户请求参数从工厂类里获取一个对象:
class Base_Factory {
public static function getWriter() {
// 获取请求中的参数
$format = $_REQUEST['format'];
// 找到对应的格式化类
$class = $format . 'Writer';
if(class_exists($class)) {
// 返回一个 Writer 实例
return new $class();
}
// 抛出异常
throw new Exception('Unsupported format');
}
}
运行代码
是时候将所有创建的类组合起来运行了
$article = new Base_Article('shanhuhai', 'Steve', time(), 0);
try {
$writer = Base_Factory::getWriter();
}catch (Exception $e){
$writer = new XMLWriter();
}
echo $article->write($write);
我们实例化了一个 Article 对象,通过工厂模式获取到 Write对象,最后传递 Write 对象给 Article对象的 write 方法完成格式化任务。