单身人士和服务定位器的真正替代方案?

时间:2016-05-30 15:45:33

标签: php dependency-injection singleton service-locator

我正在努力提高我的编程技巧,我遇到了一个令人沮丧的问题,最好用一个例子来解释:

假设我在PHP中创建了一个microCMS。这个microCMS有一个Router类,负责路由。它还包含从中提取的URI和额外参数。

class Router{
  private $uri;
  private $params;
  ...
  public function getRoute(){ ... }
  ...
  public function getParams(){
    return $this->params;
  }
  ...
}

我还有一个Front Controller,我正在传递一个新的Router()对象。到目前为止,非常好,我可以访问前端控制器中的额外参数(通过$router->getParams();)。

class FrontController{
  private $controller;
  private $view;

  public function __construct(Router $router){
    $route = $router->getRoute();
    ...
    $params = $router->getParams(); //Yay, I can get to the params here!
    ...
    $this->view = new View($route->getModel());
    ...
  }

现在,这对我来说变得复杂了。此前端控制器构造一个视图。我希望这个View能够访问路由器的功能(例如,能够从中获取URI参数)。

class View{
  public function output(){
    //But how do I access the Router's params here...?
  }
}

第一个,最简单的解决方案似乎是将路由器变成单例或者只是将函数设置为静态并简单地调用Router::getParams() ......但是这不是因为反模式。

第二个明显的解决方案是将我的Router实例传递给View的构造函数。我想避免这种情况,因为我担心我的构造函数会在某个地方变得巨大。我不确定我需要从View中访问多少其他类,我不希望它们不必要地混淆其构造函数。这种恐惧是否合理?

另一种解决方案是使用服务定位器并在我的视图中调用类似$serviceLocator->getRouter()的内容。但显然,这也是一种反模式。

那么解决方案是什么?或者CMS的架构根本就是错误的东西?

1 个答案:

答案 0 :(得分:2)

FrontController使用Dependency Injection,这被认为是处理此问题的最佳方法。因为您直接传递了该类的实例,所以您不会创建单身人士固有的global - esque问题。

担心你的View构造函数会变得臃肿是没有根据的。如果你需要依赖,那么你需要将它注入某个地方。你不必在构造函数中执行此操作。你总是可以做一个像

这样的功能
public function setRouter(Router $router) {
     $this->router = $router;
}

并像那样注入它。

如果你的类本身确实变得臃肿,那么你需要将它重构为子类。