4

据我了解,有效的模式是:

  • 实例化所需服务(FooService)的 FooControllerFactory
  • 带有构造函数的 FooController __construct(FooService $fooService)
  • Controller 获取一些基本数据并从服务中获取结果
  • 该服务包含所有必需的业务逻辑这是一个基础服务。最终,该服务将需要其他服务来进行各种活动。例如 CacheService、SomeOtherDataService。

问题是,包含/注入这些其他互连服务的有效/适当模式是什么?

我们目前已经非常简化了一个真实的例子:

拍卖控制器

/**
  * get vehicles for specific auction
*/
public function getVehiclesAction ()
{
    $auctionService = $this->getAuctionService(); // via service locator
    $auctionID = (int) $this->params('auction-id');
    $auction = $auctionService->getAuctionVehicle($auctionID);
    return $auction->getVehicles();
}

拍卖服务

public function getAuctionVehicles($auctionID) {
    $auction = $this->getAuction($auctionID);
    // verify auction (active, permissions, ...)
    if ($auction) {
        $vehicleService = $this->getVehicleService(); // via service locator
        $vehicleService->getVehicles($params); // $params = some various conditions or array of IDs
    }
    return false;
}

车辆服务

public function getVehicles($params) {
    $cache = $this->getCache(); // via service locator
    $vehicles = $cache->getItem($params);
    if (!$vehicles) {
        $vehicleDB = $this->getVehicleDB(); // via service locator
        $vehicles = $vehicleDB->getVehicles($params);
    }
    return $vehicles;
}

建议的有效模式示例

拍卖控制器

public function __construct(AuctionService $auctionService) {
    $this->auctionService = $auctionService;
}

/**
  * get vehicles for specific auction
*/
public function getVehiclesAction ()
{
    $auctionID = (int) $this->params('auction-id');
    $auction = $this->auctionService->getAuctionVehicle($auctionID);
    return $auction->getVehicles();
}
**AuctionService**

public function getAuctionVehicles($auctionID) {
    $auction = $this->getAuction($auctionID); // no problem, local function
    // verify auction (active, permissions, ...)
    if ($auction) {
        $vehicleService = $this->getVehicleService(); // we don't have service locator
        $vehicleService->getVehicles($params); // $params = some various conditions or array of IDs
    }
    return false;
}

车辆服务

public function getVehicles($params) {
    $cache = $this->getCache(); // we don't have service locator, but cache is probably static?
    $vehicles = $cache->getItem($params);
    if (!$vehicles) {
        $vehicleDB = $this->getVehicleDB(); // where and how do we get this service
        $vehicles = $vehicleDB->getVehicles($params);
    }
    return $vehicles;
}

一些注意事项:

  • 服务仅在某些情况下相互连接,在 95% 的情况下它们是独立的
    • 拍卖有很多不需要车辆的功能
    • Vehicle 具有 VehicleController 和 VehicleService ,它们仅在某些情况下与 do Auction 相关,它是具有其他功能的独立模块
    • 在控制器中注入所有需要的服务将浪费资源,因为并非每个操作都需要它们(在现实生活中的应用程序中,我们有更多互连的服务,而不仅仅是两个)
  • 在多个服务中编写相同的业务逻辑只是为了避免使用服务定位器显然是一种无效的模式,是不可接受的。
4

2 回答 2

5

如果一个控制器需要太多不同的服务,通常表明该控制器的职责太多。

跟进@AlexP 的回答,然后该服务将被注入您的控制器中。根据您的设置,这肯定会在创建控制器时导致依赖注入级联。这至少会将创建的服务限制为控制器实际需要的服务(以及那些与传递相关的服务)。

如果其中一些服务很少需要并且您担心在每次请求时都创建它们,那么新的服务管理器现在也支持惰性服务。这些仍然可以作为常规依赖项(如上)注入服务/控制器,但仅在第一次调用时创建。

从文档的示例中复制此内容:

$serviceManager = new \Zend\ServiceManager\ServiceManager([
    'factories' => [
        Buzzer::class             => InvokableFactory::class,
    ],
    'lazy_services' => [
         // Mapping services to their class names is required
         // since the ServiceManager is not a declarative DIC.
         'class_map' => [
             Buzzer::class => Buzzer::class,
         ],
    ],
    'delegators' => [
        Buzzer::class => [
            LazyServiceFactory::class,
        ],
    ],
]);

请求服务时,它不会立即创建:

$buzzer = $serviceManager->get(Buzzer::class);

但仅在首次使用时:

$buzzer->buz();

通过这种方式,您可以将多个依赖项注入到您的控制器中,并且只会创建实际需要的服务。当然,对于任何依赖项都是如此,例如其他服务所需的服务等等。

于 2016-07-06T19:01:12.663 回答
1

您可以编写一个新服务,比如说VehicleAuctionService并使用工厂将AuctionServiceVehicleService注入作为依赖项。

这是对象组合。

class VehicleAuctionService
{
    private $auctionService;
    private $vehicleService;

    public function __construct(
        AuctionService $auctionService, 
        VehicleService $vehicleService
    ){
        $this->auctionService = $auctionService;
        $this->vehicleService = $vehicleService;
    }

    public function getAuctionVehicles($auctionID)
    {
        $auction = $this->auctionService->getAuction($auctionID);

        if ($auction) {
            $params = [
                'foo' => 'bar',
            ];
            $this->vehicleService->getVehicles($params);
        }
        return false;
    }

}
于 2016-07-06T16:38:34.520 回答