前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP多态极其应用

PHP多态极其应用

作者头像
用户8568307
发布2022-03-14 14:56:57
2920
发布2022-03-14 14:56:57
举报
文章被收录于专栏:PHP全栈技术

php多态

多态,作为面向对象编程中的一种设计模式,指的是通过遵循同一个interface,类可以有不同的功能实现(相当于说有多种形态)。

interface(广义上的接口),多态里面很关键的一环就是接口,广义上的接口包括interface 和 abstract class

接口和抽象类解释

interface

interface里可以定义方法名及相应参数,任何实现这个interface的类必须具体实现interface里定义的所有抽象方法,一个class可以实现多个interface。

代码语言:javascript
复制
interface MyInterface {
    public function doThis();
    public function doThat();
    public function setName($name);
}

// 正确的做法
class MyClass implements MyInterface {
    protected $name;
    public function doThis() {
        // code that does this
    }
    public function doThat() {
        // code that does that
    }
    public function setName($name) {
        $this->name = $name;
    }
}
 
// 无效的做法
class MyClass implements MyInterface {
    // 缺少 doThis()方法!
 
    private function doThat() {
        // 这个方法必须也是public!
    }
    public function setName() {
        // 缺少 name 参数!
    }
}

abstract class

abstract class 可以说是介于interface 和普通class之间,它既可以通过abstract method的形式定义统一的接口,又可以定义具体的实现。一个扩展了改abstract class 的普通class ,必须具体实现该abstract class的所有抽象方法。

代码语言:javascript
复制
abstract class MyAbstract {
    public $name;
    public function doThis() {
        // do this
    }
    abstract public function doThat();
    abstract public function setName($name);
}

多态实现

假设你有一个article class

代码语言:javascript
复制
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;
    }
}
代码语言:javascript
复制

现在呢,你想添加一个方法,来以不同的形式输出article相关的信息,比如说XML格式,或者说JSON格式。

可能我们一开始会想着这么来处理:

代码语言:javascript
复制
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下,硬要去做太多的事情了。那么这个时候,也就是该尝试多态实现了。

01 首先定义一个interface

代码语言:javascript
复制
interface Writer {
    public function write(Article $obj);
}

02 具体实现interface

XMLWriter可以这样来实现:

代码语言:javascript
复制
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:

代码语言:javascript
复制
class JSONWriter implements Writer {
    public function write(Article $obj) {
        $array = array('article' => $obj);
        return json_encode($array);
    }
}

这样每一个class只负责各自的那一件事。

03 具体调用

代码语言:javascript
复制
class Article {
    //...
    public function write(Writer $writer) {
        return $writer->write($this);
    }
}
代码语言:javascript
复制

这样article的write方法接收的是一个实现了Writer这个interface的具体类,article不再需要关注具体该用什么样的格式,那已经不是它要负责的了,交给背后具体的Writer去处理就好了。

至于怎么传一个具体的writer进去,这个就取决于你的使用情境了,比如你可以用一个factory class来这样操作:

代码语言:javascript
复制
class Factory {
    public static function getWriter($format) {			
        // 形成相应的class name,并检查该class是否存在
        $class =  $format . 'Writer';
        if(class_exists($class)) {
            // 返回一个具体实例
            return new $class();
        }
        // 否则的话抛出异常
        throw new Exception('Unsupported format');
    }
}

04 终端调用

代码语言:javascript
复制
$article = new Article();
 
try {
    $writer = Factory::getWriter('json');
}
catch (Exception $e) {
    $writer = new XMLWriter();
}
 
echo $article->write($writer);
代码语言:javascript
复制

这里呢只是展示了多态的一种应用案例,供大家初步了解interface的益处和必要性:interface就像一个“蓝图”,基于这个“蓝图”,你可以放心地去实现多种形态的功能,从而使你的程序更加地模块化、易于扩展。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PHP全栈技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档