【问题标题】:Facade pattern for Symfony2 servicesSymfony2 服务的外观模式
【发布时间】:2015-06-02 19:27:24
【问题描述】:

Symfony2 的新手,我正在构建一个使用外部 API 获取数据的应用程序。我创建了许多客户端类来从 API 检索和转换每个实体,并将这些类定义为服务 - 例如,我有一个 FooClientgetAll()getThoseThatInterestMe($me) 之类的方法,它们从 API 返回数据.

现在我想创建一个ApiClientFacade 类,它充当所有XxxClient 类前面的接口,紧随Facade Pattern - 例如,这个外观类将有一个方法getAllFoo(),它在turn 会调用FooClient::getAll(),依此类推...

我也可以将我的外观类定义为服务,但是它有太多的依赖项——我有大约 30 个客户端类。此外,使用这种方法,我每次都会加载所有 30 个依赖项,而大多数时候我只需要一个依赖项......

那么,有没有更好的方法来做到这一点?

【问题讨论】:

  • 虽然通常不鼓励,但有时注入完整的容器是可以接受的。拥有 30 多个潜在依赖项,只需注入容器并根据需要提取依赖项。
  • 我实现了与您在 Symfony2 中所要求的类似的东西。我使用了工厂模式、一个抽象基础服务和许多标记子服务。然后使用 CompilerPassbundle 的构建方法 中添加到容器中,以便将 argument 添加到标记的类的定义中服务。这个参数是类名,所以工厂可以实例化它。在我的情况下,所有子服务都具有相同的依赖项,在父项中声明。我不确定这是否会(有)帮助(ed)你。

标签: symfony service facade


【解决方案1】:

使用额外的 ApiClientFactory 将有关“ApiClient 对象实例化”的责任从您的 ApiFacade 类转移(据我了解,这是您最初的想法)。

在一些伪 php 代码中,我的想法是:

$api = new ApiFacade(new ApiClientFactory);
$api->sendNotificationAboutUserLogin('username', time());

方法示例:

class ApiFacade {
  private $apiFactory;

  public function __construct(ApiClientFactory $factory)
  {
      $this->apiFactory = $factory;
  }    
  public function sendNotificationAboutUserLogin($username, $timeOfOperation)
    {
      return $this->apiFactory
          ->createApi('User')
          ->post(
              'notifications',
              array('operation' => 'login', 'username' => $username, 'timeOfOperation' => $timeOfOperation)
          );
    }
}

在这种情况下,您的 Facade 类保持可注入(可测试),但也变得更简单可实例化(您不再需要将所有依赖项传递给它)。

ApiClientFactory 应该如下所示:

class ApiClientFactory {
    private $apiBaseUrl;
    public function __construct($apiBaseUrl)
    {
      $this->apiBaseUrl = $apiBaseUrl;
    }
    public function createApi($apiName)
    {
      switch ($apiName) {
        case 'User': return new \My\UserApi($this->apiBaseUrl);
        default: // throw an exception?
      }
    }
}

【讨论】:

  • 因为您的想法对于一般场景来说是有意义的,但这不适用于我使用 Symfony2 服务的场景 - 基本上,如果我尝试做类似的事情,我需要工厂类中的依赖项,所以我在不同的地方有同样的问题......
  • 但我的解决方案是不要将您的“Api”类传递给工厂的构造函数,而是:根据请求实例化它们(当 ->createApi() 调用到达工厂时)。在这种情况下,您没有这个问题。
  • 问题是 Symfony 服务不会被 new \My\UserApi($this->apiBaseUrl); 实例化!但是将UserApi 注入到类中,或者从ServiceContainer 获取它...
  • 你能举个例子吗?我不明白这一点,尽管我想帮你找到中间的解决方案。
  • 看看这个:symfony.com/doc/current/book/service_container.html 基本上,在 Symfony 中,您可以将类定义为服务,它们在服务容器中“注册”,然后通过 $container->get('service.name') 将它们从容器中获取。您还可以将服务设置为其他服务的依赖项,在这种情况下,依赖项将作为构造函数参数“注入”到依赖类中。所以,当你做new \My\UserApi() 时,这不是你创建 Symfony 服务的方式......无论如何,谢谢你的帮助,我赞成你的回答;)
猜你喜欢
  • 1970-01-01
  • 2012-08-21
  • 2018-11-11
  • 2013-03-07
  • 2016-10-18
  • 2018-11-01
  • 2013-02-06
  • 2018-04-15
  • 1970-01-01
相关资源
最近更新 更多