【问题标题】:ServiceLocator and the Open/Closed PrincipleServiceLocator 和开闭原则
【发布时间】:2010-12-26 07:56:05
【问题描述】:

我想:

  1. 使所有需要它们的类都可以看到常用的服务,
  2. 具有最少的样板,并且
  3. 不牺牲可测试性!

这是一个小项目,我认为 DI 可能有点矫枉过正,但也许我错了?反正我一直关注ServiceLocator pattern as described by Martin Fowler

在客户端类的构造函数中,我有这样的东西:

this->db = Locator::getDb();
this->log = Locator::getLogger();

然后类的其余方法通过这些成员属性访问服务,例如:

this->fooModel = new fooModel(this->db);
fooItem1234 = this->fooModel->findById(1234);

不过,我也希望“模型”对象(如上面的 fooModel)具有这种可见性级别,因为它们可以从多个不同的地方访问,并且不需要多个实例。

所以我最初的想法是扩展 Locator 以拥有 ::getFooModel(),但现在看来我违反了开放/封闭原则,因为每次引入新模型类时我都必须修改 Locator。

为了满足 OCP,我可以使用动态服务定位器(也在 Fowler 的页面上进行了描述),但出于与他相同的原因,我并没有完全接受这一点,即它不够明确。

另一个解决方案是让我所有模型的方法都是静态的。所以:

fooItem1234 = FooModel::findById(1234);

我喜欢这个,因为它是零样板。我可以创建一个新的模型类,然后从任何地方用一行代码开始调用它。但是现在该模型依赖于 Locator 来找到它的数据库连接,我不确定我对此有何感受。一方面,如果我需要在单独的数据库连接上打开两个 fooModel,那将是一团糟和/或不可能。也就是说,我目前实际上不需要这样做,所以这个选项似乎有点诱人。

最后,还有 DI。但就像我上面所说的,我认为这个小项目可能太多了。

结论:我有点卡在这里,希望 StackOverflow 大师的一些建议!

【问题讨论】:

    标签: php design-patterns oop dependency-injection


    【解决方案1】:

    为什么您认为 DI 对您的项目来说太过分了? Constructor Injection 等 DI 模式比 Service Locator(我认为它是一种反模式)更简单、更干净。

    我认为 Service Locator 是一种反模式,因为它对 API 的用户完全不透明,哪些依赖项需要到位;因此,可以在服务定位器抛出的上下文中轻松调用对象上的方法,而 API 绝对不会让您知道情况是否如此。

    您不需要 DI 容器即可使用 DI。如果只是有一个简单的项目,您可以使用所谓的 Poor Man's DI 手动连接依赖项。

    【讨论】:

    • 是的,当我说我认为 DI 会矫枉过正时,我的意思是使用容器,抱歉。并感谢您的回答!当您说构造函数注入时,我接受它,您是说我应该将我的 dbconn 和记录器对象传递给依赖它们的类的构造函数?如果是这样,这实际上就是我正在做的。然后,出于某种原因,我决定将记录器添加到每个类的构造函数原型中是不好的。但是现在你让我考虑了它,它似乎比我一直试图用这个 ServiceLocator 做的更有意义。
    • 酷。然后,您通常最终会做的是堆叠或包装依赖项。您可能会有很多低级服务,但您通常可以将其中的两个或三个包装在有意义的对象中,然后只注入其中一个而不是三个低级服务。您可以多次重复此操作,以减少各个类的依赖项数量。
    • 如何将不完全相关的东西(例如我上面示例中的 DBconn 和记录器)堆叠/包装到一个名为“config”的对象中,或者这种形式不好?
    • 如果它在您正在建模的领域中有意义,这听起来是一个绝妙的主意;如果他们真的不相关,那不是。最后,我们跳过了所有这些障碍,使代码更易于维护,而且只有尽可能地直观,我们才能成功。
    • OK.. 我猜“相关”的定义可能会有所不同 :) 我本来想问你另一个问题,但我想我们正在远离原来的主题,所以我把它贴在这里: stackoverflow.com/questions/1900562/…有时间请查看!
    【解决方案2】:

    ...而且没有必要拥有多个实例。

    您正在混合苹果和橙子。应用程序只需要一个类的实例这一事实与使该实例全局可用是一个好主意不同。使用 DI,您不会更改基数 - 仍然只有一个实例。您更改的是解决所述实例的变量范围。有区别。

    【讨论】:

      猜你喜欢
      • 2017-12-01
      • 2011-06-28
      • 1970-01-01
      • 1970-01-01
      • 2018-03-17
      • 1970-01-01
      • 2021-11-06
      • 2016-09-12
      • 1970-01-01
      相关资源
      最近更新 更多