假设我的接口CrawlerInterface
包含实施PageCrawler
和FeedCrawler
;如果我们碰巧需要在控制器中同时使用这两个类,那么如何使用构造函数注入实现呢?
以前我们使用中心ServiceProvider
注册(即App::bind
)这样的类,但在大多数情况下我们只有1个接口的实现,所以我们还没有遇到过这个问题。
PS:我也想知道这个问题是否表明我们应该拆分控制器。
更新
感谢您的评论和回复,解释说,界面只有一个公共方法:crawl($uri)
,并且页面/ Feed抓取工具都将其实现为given a resource identifier, return resource.
我的跟进问题:
假设我们处于calculator
场景中,其中加法,减法和乘法共享相同的接口Operation
,其中只有一个公共方法run
,在某些时候我们仍会遇到此问题对吗?我们如何使用ServiceProvider
处理这些情况?
答案 0 :(得分:13)
如果每个抓取工具因不同原因而存在,您可以为实例使用任意名称,例如:
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());
}
// ...
}
答案 1 :(得分:5)
好的,假设你有一个CrawlerController
class CrawlerController extends BaseController
{
protected $crawler1;
protected $crawler2;
public function __construct(CrawlerInterface $c1, CrawlerInterface $c2)
{
$this->crawler1 = $c1;
$this->crawler2 = $c2;
}
}
界面
interface CrawlerInterface{}
该intefrace的具体实现称为PageCrawler
和FeedCrawler
class PageCrawler implements CrawlerInterface{}
class FeedCrawler implements CrawlerInterface{}
您可以通过编写像
这样的服务定位器来注入依赖项App::bind('CrawlerController', function($app) {
$controller = new CrawlerController(
new PageCrawler,
new FeedCrawler
);
return $controller;
});
但正如其他人所建议的那样,你应该重新思考你的逻辑,只有这样才能使用它 建筑是不可避免的
答案 2 :(得分:3)
我认为在这种情况下界面不会帮助你。
通过做:
App::bind('CrawlerInterface', '<implementation>');
您需要选择一个:
App::bind('CrawlerInterface', 'PageCrawler');
或
App::bind('CrawlerInterface', 'FeedCrawler');
然后Laravel会注入它:
class CrawlerController {
public function __construct(CrawlerInterface $crawler)
{
}
}
让两者都有两个选项
- 有2个不同的界面
- 直接注入实现:
class CrawlerController {
public function __construct(PageCrawler $pageCrawler, FeedCrawler $feedCrawler)
{
}
}
但我也认为,如果你需要这样的东西,你最好重新考虑一下你的逻辑。