Как добавить несколько классов, которые используют один и тот же интерфейс в Laravel 4

Скажем, у меня есть интерфейс CrawlerInterface с реализацией PageCrawler и FeedCrawler; если нам понадобятся оба класса в контроллере, как это может быть достигнуто при вводе конструктора?

Раньше мы использовали центральный ServiceProvider для регистрации (то есть App::bind) таких классов, но в большинстве случаев у нас есть только 1 реализация интерфейса, поэтому эта проблема еще не произошла с нами.

PS: Я также задаюсь вопросом, предполагает ли эта проблема разделить контроллер.


Обновление:

Спасибо за комментарии и ответ, чтобы объяснить, что интерфейс имеет только один общедоступный метод: crawl($uri), и оба искателя страницы/фида реализуют его как given a resource identifier, return resource.


Мой следующий вопрос:

Скажем, что мы находимся в сценарии calculator, где добавление, вычитание и умножение имеют один и тот же интерфейс Operation, который имеет только 1 открытый метод run, в какой-то момент мы все равно столкнемся с этой проблемой правильно? Как мы вообще обрабатываем такую ​​ситуацию с помощью ServiceProvider?

Ответ 1

Если каждый искатель существует по другой причине, вы можете использовать произвольные имена для своих экземпляров, например:

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());
    }
    // ...
}

Ответ 2

Ok позволяет предположить, что у вас есть CrawlerController

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

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

интерфейс

interface CrawlerInterface{}

и конкретные реализации этой функции, называемой PageCrawler и FeedCrawler

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

Вы должны вводить зависимости, записывая локатор службы, например

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

Но, как было предложено другими, вы должны пересмотреть свою логику, использовать ее только в том случае, если этот вид архитектуры неизбежно

Ответ 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)
    {
    }

}

Но я также думаю, что если вам нужно что-то вроде этого, вы лучше переосмыслите свою логику.