将接口参数视为具体参数是一种不好的做法吗?


Is it a bad practice to consider an interfaced parameter as a concrete one?

我有以下类:

<?php
class SaveEvent implements EventInterface
{
    private $_path;
    public function __construct($path) { $this->_path = $path; }
    public function getName() { return 'save'; }
    public function getPath() { return $this->_path; }
}
class Observer implements ObserverInterface
{
    public function update(EventInterface $event)
    {
        switch ($event->getName()) {
            case 'save':
                $path = $event->getPath();
                file_put_contents($path, 'File saved');
                break;
            case 'quit':
                // Other event
        }
    }
}

正如你所看到的,我的"update"方法接受一个EventInterface参数,并根据事件的类型触发一个特定的进程。它的实现与SplSubject/SplObserver差不多,但不是将主题传递给观察者,而是传递一个事件(最终可以包含数据)。

我的观察者将监听一个"save"事件,事件链接到一个文件路径,并将字符串" file saved"存储在这个路径上。

接受一个"接口"参数,检查它的具体类型,然后把它看作是它的具体类型,这是一个不好的做法吗?

如果是,您有什么解决方案?

PS:我对我为这个主题设置的标题和标签不满意,如果你有更好的请帮助我:)

我在这里看到的唯一问题是您期望该接口的几个特定实现之一。如果您正在优化,有时这是可以的,但我通常希望看到声明的类名,例如:

if ($event instanceof MyConcreteEvent) {
    // ...
}

如果您正在实现一个事件调度程序,那么您将向侦听特定$event->getName()Observer订阅类。

然后,观察者将遍历订阅者,调用每个订阅者。如果没有订阅者侦听该事件,则不会发生任何事情。

查看http://symfony.com/doc/current/components/event_dispatcher/index.html获取事件信息。

我知道Observer和Event Dispatcher是不同的模式,但本质上它们是一样的

这是一个很好的实践,因为您可能有另一个类(实现相同的接口)具有类似/确切的行为,但使用不同的算法,并且可以很容易地解耦。

这是一个策略设计模式(查看更多模式在这里:http://www.phptherightway.com/pages/Design-Patterns.html#strategy)

    class YYYScraper implements LinkScraper
    {
        public function getLinks() {
        //gets links from the site www.yyy.com specific for this because the site has a different structure from the class below
        } 
    }
    class XXXScraper implements LinkScraper
    {
        public function getLinks() {
        //gets links from the site www.xxx.com
        } 
    }
class ProcessService
{
    public function gatherLinks(LinkScraper $linkScraper)
    {
        $linkScraper->getLinks();
        //save them or smth
    }
}

在您的示例中,update方法变得越来越大,并且做得太多。它变得难以阅读。

最好的选择是将每个事件类型实现为观察者类中的方法,如:
class Observer implements ObserverInterface
{
    public function save(SaveEvent $event)
    {
        $path = $event->getPath();
        file_put_contents($path, 'File saved');
    }
    public function quit(QuitEvent $event)
    {
        // Other event
    }
}

希望能有所帮助。

相关文章: