【问题标题】:Zend Framework 2 Architecture (how to reduce coupling between modules)?Zend Framework 2 Architecture(如何减少模块之间的耦合)?
【发布时间】:2012-11-12 17:16:48
【问题描述】:

一个 ZF2 系统中有许多组件。每个组件都有自己的表示层、业务层和数据层。问题是当组件 Foo 有一个使用组件 Bar 的数据层的控制器时。

示例:

<inside modules, each module can be individually deployed or removed>
\modules
   \Foo                  ; one module (this directory) can be added or removed
     \view               ; presentation layer (view) for all subcomponents
        \Subcomponent1
            \Action1
        \Subcomponent2
            \Action2
        ...
     \src
        \Subcomponent1
            \Entity      ; data layer     (model)
            \Controller  ; business layer (controller)
            \Service     ; service layer  (service)
        \Subcomponent2
            \Entity
            \Controller
            \Service
        \Subcomponent3
            ...
  \Bar
     \view
         ...
     \src
         \Subcomponent1
            ...
  \Baz
     \src
         \Subcomponent1
            ...

子组件与来自其他子组件的实体强耦合,通常来自完全不同的组件。控制器和服务就是这种情况。可以解决吗?

Foo\Subcomponent1 有一个 FooSub1Service,它使用 Bar\Subcomponent1 中的实体来处理传递的数据并将它们导入 DB。 Baz\Subcomponent1 有一个 AuthenticationService,它使用 Bar\Subcomponent1 实体通过 ID 等查找用户。

我知道依赖注入,但在这种情况下,每个子组件中都有 EntityManager,它被指示按名称和 PK 查找实体,即 find("Bar\Subcomponent1\Entity\User", 123)。而且,当持久化实体时,我必须实例化任何具有外键的东西,即 UserAddress 并将其添加到 User。每次调用 x = new NameOfEntity() 时,我都会将子组件与子组件中的某个实体紧密耦合,通常来自不同的系统模块。

【问题讨论】:

  • 如果 ZF2 是面向方面的,我会将这些横切关注点(例如持久性)解耦到方面。麻烦的是,它只是 OOP。模块化的损失是不可避免的吗? en.wikipedia.org/wiki/Cross-cutting_concern
  • 如果您遵循工厂模式,您不应该发现模块之间存在依赖关系,并且从架构的角度来看,共享组件可能应该位于所有模块都可以访问的库文件夹中。

标签: php architecture zend-framework2 software-design


【解决方案1】:

在 ZF2 中,可以使用 EventManager 减少模块之间的耦合,另请参阅 here

此外,module/config/module.config.php 用作Facade

所有实体都可以在任何模块的module/config/module.config.php 文件中定义ONCE。然后其他模块可以使用ServiceManager 来解决它们的依赖关系。

ServiceManager 实现了Service Locator pattern

使用 Facade (module.config.php) 和 EventManager,成功减少了模块之间的耦合。

【讨论】:

    【解决方案2】:

    您不能总是删除所有依赖项。例如,身份验证模块通常依赖于某种形式的用户凭据。

    减少与特定类耦合的一种方法是允许使用适配器替换依赖项。

    例如,如果您希望能够与身份验证模块一起使用不同类型的用户模块,您可以在身份验证模块中定义一个接口,该接口必须由用户模块中的适配器实现,以便它能够与之兼容。然后,为您的 auth 模块添加一个配置选项,允许用户更改使用的用户适配器实现。

    根据复杂性,您还可以简单地为对象本身定义特定的接口,而不是使用适配器。但是,这有时可能会在对象中添加不相关的功能等,可能会使它们的实现更难理解。

    最后,我建议不要尝试在您的代码中实现太多这样的灵活性。除非您计划与世界共享您的模块,否则您不太可能需要它,因为只需更改模块中具有硬依赖的几行代码通常会简单得多,而不是编写全新的接口和类.这显然是您需要根据您计划如何使用这些模块来评估自己的事情。

    【讨论】:

    • 适配器和接口已经被用来解耦一些依赖。问题特别在于实体,因为许多不同的模块/子组件从其他地方访问实体。这是一个横切关注点,它使系统的模块化程度降低。即我们改变了一个实体,一切都需要改变。你看到问题了吗?也许应该有一些门面。 ZF2有什么解决办法吗?
    • @MarekCruz 我不认为 ZF2 真的为此提供了任何东西。如果您熟悉使用某些 aop 库,您可能会考虑使用这些库来帮助您。应该没有任何理由不能与 ZF2 一起使用。
    【解决方案3】:

    不要直接访问实体或存储库。 每个模块实现一个或多个服务,你可以给他们一个接口来明确这一点。

    如果您使用像 ORM Doctrine 2 这样的数据层,那么每个模块中的每个 /entity 文件夹无论如何都是共享的。这样就可以在一个存储库中进行连接并获取连接的实体。这还不错。

    不要仅仅为了减少依赖而滥用事件管理器。使用共享服务并仅使用这些服务。

    当您想要调用整个应用程序并收集东西或需要答案时,请使用事件管理器。

    【讨论】:

      猜你喜欢
      • 2013-02-05
      • 1970-01-01
      • 1970-01-01
      • 2017-08-09
      • 2017-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多