我正在从Controller中将代码提取到Symfony 3.4 App中的一种ApplicationService。
我有一个用于抓取数据的具体类,还有另一个用于更改某些数据的具体转换器。
src\App\Service
class CompanyScraping implements ScrapingInterface
{
private $crawler;
public function __construct(CrawlerInterface $crawler)
{
$this->crawler = $crawler;
}
public function extract()
{
...
}
public function transform()
{
$transformer = new concreteTransformer();
}
}
class concreteTransformer
{
private $em;
public __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
}
如果未在CompanyScraping类中调用EntityManager,如何将EntityManager传递给concreteTransformer类?我无法使用新实例化ConcreteTransformer。
我在考虑这两个选项:
将EntityManager传递给CompanyScraping,但我认为这是一个错误的主意,因为CompanyScraping不需要此依赖项。
将转换方法提取到另一个类中,并从控制器/控制台传递em
$crawler = new CompanyScraping(new GoutteClient());
$rawData = $crawler->extract(...);
$data = new concreteTransformer($em, $rawData);
还有其他想法吗?
谢谢。
我想到的第一个解决方案是将(不是EM,而是)将Transformer注入Scraper类,如评论中所述。
但是,这种解决方案无法解决潜在的问题:Scraper是抓取,转换还是两者同时进行?在后一种情况下,它不遵循单一责任原则,因为它既负责抓取和转换,又负责。
一种可以非常有效地解决此问题的设计模式是decorator pattern。在这种情况下,其想法是通过转换“装饰”刮取的结果。
结果看起来像这样:
class Transformer implements ScrapingInterface { private $scraper; private $em; public __construct(ScrapingInterface $scraper, EntityManagerInterface $em) { $this->scraper = $scraper; $this->em = $em; } public function extract() { return $this->transform($this->scraper->extract()); } private function transform() {...} }
它可以构造为:
$crawler = new Transformer(new CompanyScraping(new GoutteClient()), $em);
如果您有多个转换器实现,则可以使装饰器更加通用:
class TransformingScraper implements Scraper
{
private $scraper;
private $transformer;
public __construct(Scraper $scraper, Transformer $transformer)
{
$this->scraper = $scraper;
$this->transformer = $transformer;
}
public function extract()
{
return $this->transformer->transform($this->scraper->extract());
}
}
$crawler = new TransformingScraper(
new CompanyScraping(new GoutteClient()),
new ConcreteTransformer($em)
);