“控制器”和“gui”之间的循环依赖

时间:2011-11-02 20:52:04

标签: design-patterns language-agnostic circular-dependency

我正在用Java编写一个复杂的GUI,其中有许多组件在多个屏幕上工作,并与共享的逻辑和模型进行交互。显然,“gui”和“controller / logic”之间存在一些循环依赖关系:GUI中的用户操作被转发到控制器,控制器执行某些任务,然后需要在所有GUI中反映这些更改。在后台可能会发生一些事情,使控制器推送更新到GUI。等等。

现在,这是我的问题。监听器或观察器模式非常适合将更新推送到GUI。可以让我的GUI直接依赖于具体的控制器类吗?为什么/为什么不呢?有(并且总是会)只有一个这样的控制器。 GUI有十几个控制器调用,用于轮询状态和执行操作 - 我不喜欢一些简单的回调接口的想法,这些回调接口总是只有一个实现,也没有一个巨大的回调接口供所有人使用各种行动。

3 个答案:

答案 0 :(得分:6)

  

可以让我的GUI依赖于具体的控制器类   直?为什么/为什么不呢?

否:因为loose coupling是良好设计的基础。取决于抽象。根据实现,不可能在不重新编译依赖项的情况下将一个实现替换为另一个实现。紧密耦合任何两个类都会妨碍未来的灵活性。

是的:这是一个判断电话。如果松散耦合肯定没有未来的好处,并且太昂贵而无法证明,那么请将其结合起来。

但是真的尽量不去。让GUI依赖于控制器是一个有效的设计决策。但总是依赖于抽象,从不实现。来吧......你知道的。我的意思是,好吧,如果没有人希望关闭控制器,那么你没有通过使用接口获得任何东西。除了安心,知道你写了更整齐,更少耦合的代码。并且可以说更容易测试。

至于如何选择GUI和控制器之间的通信,这是一个折腾。您可以使用事件,但是将它们连接起来是一种阻力,它们不会跨越应用程序边界。但通过使用事件,您可能会觉得您有最松散的耦合。除了最初连接事件之外,GUI和控制器永远不需要相互寻址(抽象)。那可能会感觉很好。或者你可以使用对接口的方法调用,这可能感觉像一个稍微紧凑的耦合,但它真的几乎没有。无论如何,X 必须知道有关Y的事情,以便他们进行交流。

GUI和控制器之间的循环依赖关系是可以的(在抽象上!)。 MVC模式有许多变体。每次我使用它,我都会根据自己的需要/情绪来塑造它。也就是说,我确实尝试避免循环依赖。我更喜欢将依赖关系限制在一个方向。或者根本没有!

例如,在我当前的项目中,控制器知道视图,但视图完全不知道控制器退出。控制器会触发视图的事件,并通过视图绑定的单个状态对象将数据传回给它们。状态类是视图唯一依赖的东西。控制器唯一知道的是视图的界面和状态对象的类型。这些东西在外部模块中定义,以便可以完全删除视图模块,控制器仍然可以编译,反之亦然。这是一个非常松散的耦合。几乎没有(双方都取决于第三个模块)。

有些人以相反的方式做到这一点。

避免具体依赖的原因

  • 难以将一个实现交换为另一个实现 - 依赖可能需要修改或至少重新编译
  • 难以维护 - 无法彼此独立地修改组件
  • 难以隔离测试 - 需要修改和重新编译依赖项以交换依赖项的模拟实现

答案 1 :(得分:1)

我完全赞同@Charles说:

  

松耦合是良好设计的基础。

原因很清楚,他已经解释过了。 我想与你分享一个与MVC略有不同的模式,其中视图和控制器是同一个实体。 它被称为Model-Delegate,它被Swing使用。链接的文章深刻地描述了它。

答案 2 :(得分:0)

我不是MVC / MVP的专家,但这是我大部分时间都在做的事。

对于UI自动化和测试不成问题的简单应用程序,我根据具体的控制器使用GUI(我的视图实际上是实例化控制器)。我做的是确保GUI实现一些控制器在其构造函数中作为参数的视图接口。 这样,我不需要使用任何事件或类似观察者的行为:控制器可以访问视图界面,​​视图将控制器作为其成员。 在我看来,这种方法的问题在于它并不是真正的测试友好。虽然有些人可能认为MVP(模型视图展示者)可能基于这种方法,但我不喜欢没有实例化GUI对象的情况下控制器不能存在的事实。即使您在其构造函数中将控制器作为GUI对象的参数传递,我也倾向于认为它更像是一个hack。 该方法的另一个问题是GUI实际上不够passive。我喜欢我的UI中的逻辑由控制器处理,而不是相反。但这可能只是个人选择。

对于测试成为大问题的更高级应用程序,我确保GUI甚至不知道控制器,因为控制器是实例化GUI对象的(直接或使用依赖注入)。 supervising controller行中的某些内容。这种方法对测试有很大帮助,因为我实际上可以通过提供虚假的GUI实现来模拟整个UI,甚至可以使用不同的视图实现来重用我的控制器。在这种情况下,UI实际上可以引发控制器将处理的事件,但只有控制器才会修改底层模型或者在需要时将修改推送到View(而不是从控制器“拉”“数据”来更新自身。)

只是我的2美分......