【问题标题】:Separation of domain and ui layer in a composite组合中域和 ui 层的分离
【发布时间】:2011-01-04 09:38:05
【问题描述】:

我想知道是否有一种模式可以将类的域逻辑与域层中对象的 ui 职责分开。

例子:

// Domain classes
interface MachinePart
{
    CalculateX(in, out)
    // Where do we put these:
    // Draw(Screen)  ??
    // ShowProperties(View)  ??
    // ...
}

class Assembly : MachinePart
{
    CalculateX(in, out)
    subParts
}

class Pipe : MachinePart
{
    CalculateX(in, out)
    length, diamater...
}

有一个应用程序可以计算由许多机器零件组装而成的机器的 X 值。程序集从文件表示中加载,并被设计为组合。每个具体的零件类都存储一些数据来实现CalculateX(in,out) 方法来模拟整个装配体的行为。该应用程序运行良好,但没有 GUI。为了提高可用性,应在现有实现之上开发 GUI(允许对现有代码进行更改)。 GUI 应显示装配的示意图,并提供特定于零件的对话框来编辑多个参数。

为了实现这些目标,应用程序需要为每个机器部件提供新功能,以便在屏幕上绘制示意图、显示属性对话框和其他与机器仿真领域无关的内容。我可以想出一些不同的解决方案来为每个部分实现Draw(Screen) 功能,但我对每个部分都不满意。

首先我可以向 MachinePart 接口添加一个 Draw(Screen) 方法,但这会将域代码与 ui 代码混淆,我必须向每个机器部件类添加很多功能,这使得我的域模型难以阅读和很难明白。

另一个“简单”的解决方案是让所有部分都可访问并在访问者中实现 ui 代码,但访问者不属于我最喜欢的模式。

我可以从每个机器部件类派生 UI 变体以在其中添加 UI 实现,但我必须检查每个部件类是否适合继承,并且必须小心更改基类。

我目前最喜欢的设计是创建一个并行复合层次结构,其中每个组件存储数据以定义一个机器部件,具有 UI 方法的实现和一个创建相应域类实例的工厂方法,以便我可以“转换” UI 程序集到域程序集。但是,从创建的域层次结构返回到 UI 层次结构以在图形中显示计算结果时存在问题(假设某些部分在计算过程中存储了一些值,我想在模拟后在示意图中显示)。

也许这些问题有一些经过验证的模式?

【问题讨论】:

    标签: model-view-controller user-interface design-patterns domain-driven-design


    【解决方案1】:

    同意@Marjin,并概括他的答案。您需要的是Model-View-Controller,其中 MVP 和 MVVM 是变体。从您的 cmets 我认为您了解这一点,但需要了解如何实现该模式。在不了解您的语言和目标架构的情况下,很难给出绝对的细节。尽管如此,我还是从Observer 模式开始(链接有示例代码)。

    您正在处理的问题是如何提供从域到 UI 的可观察访问 - 而不用特定于 UI 的代码妨碍域。 Observer 提供了一种方法来做到这一点。它确实需要域更改,特别是启用观察者注册和更改通知。但是,其中没有任何特定于 GUI 的内容,因此它可以很好地封装。

    hth.

    PS:如果您的应用程序是典型的瘦客户端 Web 应用程序,您需要修改方法。请注意:许多 Web 应用程序框架都标榜为“MVC”,但其实现在架构上与观察者模式完全不同。

    【讨论】:

    • 您说得对,域类中的观察者注册不会将 ui 代码添加到域中。但我的主要问题不是何时绘制域对象,而是如何绘制。 MachinePart 组合的客户端代码只知道域“计算”的抽象,不知道具体的组件,因此它不知道如何绘制它。每个 MachinePart 都可以说“在绿色矩形中画一个红色圆圈”,但这不是域的一部分,我不想让我的域代码负担这些知识。
    • 每个 OP 您需要两个层次结构,一个用于域类,一个用于 UI 类。简单地说,每个领域类都有一个相应的 UI 类,它知道如何绘制该部分类型。域类及其对应的 UI 类使用 Observer 连接(我不会让 UI 类从域对应物继承)。每个 UI 子类都有一个 draw() 方法,该方法将为其对应的域类呈现适当的形状。遍历结构将落入Assembly 的 UI 对应项,draw() 将迭代 Assembly.subParts
    【解决方案2】:

    您可以查看model-view-presenter (mvp)model-view-viewmodel (mvvm) 模式。

    Fowler 的presentation model 包括两个示例应用程序;你也可能对它感兴趣。

    我认为调查这些模式会给你一些关于如何继续的想法。 Mvvm 看起来很像您当前的解决方案;所以如果我是你,我会从那里开始。

    【讨论】:

    • 我阅读了很多 MVC、MVP、MVXYZ、被动视图...文章,都告诉我将业务逻辑与 ui 代码分开,但没有告诉我如何在现实世界的示例中进行分离。我在所有 gui 项目中都遵循指南,但是当它不像 DrawText(mymodel.GiveMeText) 那样简单时会遇到麻烦。 mvvm 似乎是特定于 ms 的模式(这不是 .NET 项目)。我只能找到非常技术性的 C#/WPF 文章。我需要一个更通用的模式。
    • MVVM 在 MS .net 上下文中被讨论了很多,但并不完全是“特定于 MS 的”。 Java 中的 MVVM 在link 1 之前已在 SO 上讨论过 | link 2
    【解决方案3】:

    也许View Helper 可以提供帮助。它不是 C++,而是 Java EE 模式,但在您的情况下,它肯定会将您的域对象与其表示细节分开......

    【讨论】:

      猜你喜欢
      • 2012-09-26
      • 2022-01-15
      • 2022-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多