前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >php设计模式(二十四):访问者模式(Visitor)

php设计模式(二十四):访问者模式(Visitor)

作者头像
陈大剩博客
发布2023-07-09 14:04:00
2550
发布2023-07-09 14:04:00
举报
文章被收录于专栏:陈大剩博客专栏

访问者模式

访问者模式又称为:Visitor。访问者模式是一种行为设计模式,它能将算法与其所作用的对象隔离开来

访问者模式表示一个作用于某对象结构中各元素的操作。它可以在不修改各元素类的前提下定义作用于这些元素的新操作,即动态的增加具体访问者角色

也就是说访问者模式是适用于 稳定的结构什么是稳定的结构呢? 稳定结构是指我们的对象在早之前已经开发好了,功能都实现好了(前面版本)。访问者模式是说现在我们突然要给这个开发好的结构(稳定结构),在不影响原来稳定的基础上,增添一些职责或者功能,所以说访问者模式是马后炮行为。

访问者模式是利用了双重分派。先将访问者传入元素对象的 Accept 方法中,然后元素对象再将自己传入访问者,之后访问者执行元素的相应方法。

问题

假设我们已经编写好一个操作(打开、关闭、或者内容) Pdf、Word、Xml 文件代码,现在突然我们顶头上司,需要我们实现将这些文件里的文字内容导出到 Txt 文件中。

我们可能会对每个文件对象中都写一个将内容导出 Txt 文件的方法。

过了几天顶头上司又要我们写一个将这些文件内容导出成 图片 可视化格式(类似截图内容),我们又在每个文件对象中都写一个将内容导出 图片 文件的方法。

问题是我们后面可能顶头上司会让我们支持导出其他更多的格式,我们如果这么一个个写的对象类中,会使代码越来越复杂且臃肿,且不说我们新增导出各种格式不会影响这个类原有功能的使用,可能到后面代码多起来我们自己都看不懂?所以我们应该怎么解决呢?

解决方法

我们可以使用访问器模式,给 Pdf、Word、Xml 文件代码提供一个访问者,以用来访问它们。

顾名思义访问者就是拜访的形式去拜访 Pdf、Word、Xml 类,所以我们 Pdf、Word、Xml 类中需要添加一个 接受访问者的方法 Accept(接受访问者的方法),然后再将当前类的传递给访问者(访问者需要有获取所有数据的权限)。

我们就做到了只要在 Pdf、Word、Xml 类代码中添加一个接受方法,再将类对象传递给访问者

具体的导出工作交个访问者具体方法去做 ,就不会导致 Pdf、Word、Xml 类代码复杂且难以维护。

可能往下看代码容易理解点,那下面就看代码吧。

结构

FileInterface:文件对象接口类。 PdfFile、WordFile、XmlFile:具体的文件类,实现文件接口类,提供访问本身内容的方法。 VisitorInterface:访问者接口类,提供操作接口方法。 FileToTxt:访问者实现类,提供具体向文件的操作方法。

代码示例

文件接口类

代码语言:javascript
复制
interface FileInterface
{
    /**
     * 接受者(接受访问者)
     * @return mixed
     * @author chendashengpc
     */
    public function accept(VisitorInterface $visitor);
}

文件具体实现类

代码语言:javascript
复制
// pdf
class PdfFile implements FileInterface
{
    public function accept(VisitorInterface $visitor)
    {
        return $visitor->PdfToTxt($this);
    }

    /**
     * 打开 PDF 文件内容
     * @return string
     * @author chendashengpc
     */
    public function openPdf(): string
    {
        return '我是 Pdf 文件内容';
    }
}

// word
class WordFile implements FileInterface
{
    public function accept(VisitorInterface $visitor)
    {
        return $visitor->WordToTxt($this);
    }

    /**
     * 打开 Word 文件内容
     * @return string
     * @author chendashengpc
     */
    public function openWord(): string
    {
        return '我是 Word 文件内容';
    }
}

// xml
class XmlFile implements FileInterface
{
    public function accept(VisitorInterface $visitor)
    {
        return $visitor->XmlToTxt($this);
    }

    /**
     * 打开 Xml 文件内容
     * @return string
     * @author chendashengpc
     */
    public function openXml(): string
    {
        return '我是 Xml 文件内容';
    }
}

访问者接口类

代码语言:javascript
复制
interface VisitorInterface
{
    /**
     * pdf 转 txt
     * @param FileInterface $file
     * @return mixed
     * @author chendashengpc
     */
    public function PdfToTxt(FileInterface $file);

    /**
     * Word 转 txt
     * @param FileInterface $file
     * @return mixed
     * @author chendashengpc
     */
    public function WordToTxt(FileInterface $file);

    /**
     * Xml 转 txt
     * @param FileInterface $file
     * @return mixed
     * @author chendashengpc
     */
    public function XmlToTxt(FileInterface $file);
}

访问者具体实现类

代码语言:javascript
复制
/**
 * 文件转 txt
 */
class FileToTxt implements VisitorInterface
{
    /**
     * pdf 转 txt
     * @param FileInterface $file
     * @return mixed
     * @author chendashengpc
     */
    public function PdfToTxt(FileInterface $file)
    {
        return $file->openPdf();
    }

    /**
     * Word 转 txt
     * @param FileInterface $file
     * @return mixed
     * @author chendashengpc
     */
    public function WordToTxt(FileInterface $file)
    {
        return $file->openWord();
    }

    /**
     * Xml 转 txt
     * @param FileInterface $file
     * @return mixed
     * @author chendashengpc
     */
    public function XmlToTxt(FileInterface $file)
    {
        return $file->openXml();
    }
}

客户端使用

代码语言:javascript
复制
$fileToTxt = new FileToTxt();

$pdf = new PdfFile();
echo $pdf->accept($fileToTxt) . PHP_EOL;

$word = new WordFile();
echo $word->accept($fileToTxt) . PHP_EOL;

$xml = new XmlFile();
echo $xml->accept($fileToTxt) . PHP_EOL;

输出

代码语言:javascript
复制
我是 Pdf 文件内容
我是 Word 文件内容
我是 Xml 文件内容

UML

访问者模式
访问者模式

优缺点

优点

  • 开闭原则。 可以引入在不同类对象上执行的新行为,且无需对这些类做出修改。
  • 单一职责原则。可将同一行为的不同版本移到同一个类中。
  • 访问者对象可以在与各种对象交互时收集一些有用的信息。当你想要遍历一些复杂的对象结构(例如对象树),并在结构中的每个对象上应用访问者时, 这些信息可能会有所帮助。

缺点

  • 每次在元素层次结构中添加或移除一个类时,都要更新所有的访问者。
  • 在访问者同某个元素进行交互时,它们可能没有访问元素私有成员变量和方法的必要权限。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-06-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 访问者模式
  • 问题
  • 解决方法
  • 结构
  • 代码示例
    • 文件接口类
      • 文件具体实现类
        • 访问者接口类
          • 访问者具体实现类
            • 客户端使用
            • UML
            • 优缺点
              • 优点
                • 缺点
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档