13

假设我有一个CrawlerInterface实现接口,PageCrawler并且FeedCrawler;如果我们碰巧在控制器中需要这两个类,那么如何通过构造函数注入来实现呢?

以前我们使用一个中心ServiceProvider来注册(即App::bind)这样的类,但在大多数情况下,我们只有一个接口的实现,所以我们还没有发生上述问题。

PS:我也想知道这个问题是否表明我们应该拆分控制器。


更新:

感谢您的评论和回复,解释一下,所述接口只有一个公共方法:crawl($uri),并且页面/提要爬虫都将其实现为given a resource identifier, return resource.


我的后续问题:

假设我们处于calculator加法,减法和乘法共享相同接口的场景中Operation,它只有一个公共方法run,在某些时候我们仍然会遇到这个问题,对吧?我们通常如何处理这些情况ServiceProvider

4

3 回答 3

14

如果每个爬虫出于不同的原因而存在,您可以为您的实例使用任意名称,例如:

App::bind('crawler.allArticles', 'PageCrawler');
App::bind('crawler.latestArticles', 'FeedCrawler');

对于控制器:

App::bind('CrawlerController', function($app) {
    return new CrawlerController(
        App::make('crawler.allArticles'),
        App::make('crawler.latestArticles')
    );
});

然后,您的控制器代码将以不同的方式使用每个爬虫:

public function showLatestArticlesAction()
    $latestArticles = $this->latestArticlesCrawler->crawl();
    // ...
}

public function showAllArticlesAction()
    $allArticles = $this->allArticlesCrawler->crawl();
    // ...
}

如果您只有一个爬虫列表,其中每个爬虫都用于同一件事,您可能想要执行以下操作:

App::bind('crawlers', function($app) {
    return [
        App::make('PageCrawler'),
        App::make('FeedCrawler'),
    ];
});

在您的控制器中,您将通过如下配置获得“爬虫”列表:

App::bind('CrawlerController', function($app) {
    return new CrawlerController(App::make('crawlers'));
});

您的控制器代码可能是这样的:

public function showArticlesAction()
    $allArticles = array();
    foreach ($this->crawlers as $crawler) {
        $allArticles = array_merge($allArticles, $this->crawler->crawl());
    }
    // ...
}
于 2013-10-14T20:44:21.383 回答
6

好的,假设你有一个CrawlerController

class CrawlerController extends BaseController 
{
    protected $crawler1;
    protected $crawler2;

    public function __construct(CrawlerInterface $c1, CrawlerInterface $c2)
    {
        $this->crawler1 = $c1;
        $this->crawler2 = $c2;
    }
}

一个接口

interface CrawlerInterface{}

该接口的具体实现称为PageCrawlerFeedCrawler

class PageCrawler implements CrawlerInterface{}
class FeedCrawler implements CrawlerInterface{}

您可以通过编写服务定位器来注入依赖项,例如

App::bind('CrawlerController', function($app) {
    $controller = new CrawlerController(
        new PageCrawler,
        new FeedCrawler
    );
    return $controller;
});

但是正如其他人所建议的那样,您应该重新考虑您的逻辑,只有在这种架构不可避免时才使用它

于 2013-10-15T00:03:43.123 回答
3

我认为在这种情况下,界面对您没有帮助。

通过做:

App::bind('CrawlerInterface', '<implementation>');

你需要选择一个:

App::bind('CrawlerInterface', 'PageCrawler');

或者

App::bind('CrawlerInterface', 'FeedCrawler');

然后 Laravel 会注入它:

class CrawlerController {

    public function __construct(CrawlerInterface $crawler)
    {
    }

}

要两者兼得,您有 2 个选择

-有2个不同的接口

- 直接注入实现:

class CrawlerController {

    public function __construct(PageCrawler $pageCrawler, FeedCrawler $feedCrawler)
    {
    }

}

但我也认为,如果你需要这样的东西,你最好重新考虑你的逻辑。

于 2013-10-14T18:53:02.367 回答