1

问题

我正在寻找(希望)一种我可能不知道的设计模式,它可以帮助完成我在下面定义的问题的一些代码分离:

我有一组代表各种实体的类,例如PointVectorArc等,它们属于二维笛卡尔平面,由 class 表示Model。该类Model充当这些实体的集合并存储有用的计算值。

我还有一个可视化界面,应该呈现模型状态的 2D 图像,并且还可以通过向模型添加实体来与模型进行小范围的交互(例如,用户可以Point通过单击向模型添加在某处的GUI上。)。

第一个想法

起初,我有一个接口Drawable,它有一个方法,Draw它可以接受一个图形上下文对象,并且实现实体会使用我正在使用的图形库(在本例中为 Java Swing/AWT)将自己绘制到该上下文中。

这很有效,因为我的应用程序的 GUI 部分只需遍历模型中的所有实体并运行它们的Draw方法来生成可视化。最大的问题是我将我的模型与它的图形表示结合起来,我觉得这是一种不好的做法。

第二个想法

我创建了一个EntityDrawer接受实体的类,根据实体类型选择正确的绘图方法,然后绘制到我的图形上下文。

这种方法实现了我一直在寻找的代码分离,但EntityDrawer该类严重依赖instanceOf/isA方法来确定如何绘制实体,我多次看到这种方法被描述为糟糕的设计。我尝试重新设计它,以便类使用重载方法来确定要使用哪种绘图方法,但我意识到这基本上是相同的instanceOf/isA以更好看的方式编写的方法。此外,对于我添加的每个新实体类,我都需要在 thisEntityDrawer的代码中进行镜像,这对我来说就像是一种耦合形式。


我希望我的模型与其图形表示之间尽可能多地解耦,以便模型可以专注于对问题进行建模,而不是如何将自己呈现到图形上下文中。此外,将来我可能会添加更多的模型实体类型,它们将具有截然不同的绘图需求。

那么,有没有一种模式或设计技术可以用来实现这一点?我觉得我提出的两种解决方案都不是最优的,并且可能有一种设计模式可以解决这类问题。

4

4 回答 4

2

在我看来,您缺少模型、视图、控制器(或 MVC)设计模式的控制器部分。

控制器将与模型通信并与视图(您的图形部分)通信,这允许您的视图和模型彼此独立。

以下是该主题的一些其他相关阅读材料: http ://www.oracle.com/technetwork/articles/javase/index-142890.html

于 2013-08-28T18:17:43.140 回答
0

我喜欢模型驱动架构和依赖注入:

http://en.wikipedia.org/wiki/Model-driven_architecture

http://en.wikipedia.org/wiki/Dependency_injection

于 2013-08-28T18:11:54.463 回答
0

在过去,我们用一个非常简单的接口将所有这些构建在一个绘图抽象层之上:在点 x,y 上放置一个颜色 c 点。

然后,我们为每种类型的对象编写了基于低级 API 的绘图类。

所以有一个 Point 类,它包含一个 PointDrawer,当有人调用它的“draw()”方法时,它会使用它。PointDrawer 知道 Point 的内部结构,它可以获取颜色、x 和 y,并调用低级 API 将点放置在显示器或纸上或从花岗岩块中凿出。

然后有一个具有颜色和两个 x,y 端点的线路呼叫。对应的 LineDrawer 知道 Line 对象的内部结构,可以创建 Point 对象并告诉它们自己绘制,也可以调用低级 API。这个选择在于实施者。另一种方法是可以向 API 添加一个新的低级方法来绘制一条线。这样就在三个不同的级别上做出了三个选择,即 LineDrawer 如何工作以将图像显示在显示器上。

对于每个新的可绘制对象,Circle、Arc、Ellipse、Box、FilledBox 等,内部都有一个相应的 XxxDrawer,它使用三个级别的某种组合进行绘制。

请注意,有些显示器内置了绘制弧线的功能,而有些则没有。这使得选择依赖于设备,因此通常会有一组“抽屉”子类。因此,可能有一个 XyzSystems4453DeviceLineDrawer 类而不是 LineDrawer 类,等等。

这非常令人困惑,但它确实允许绘制每个事物以获得最大性能(如果做动画并且你需要每秒 24 幅图像,但是图像中有 1000 多个弧线,这很有用)而且它可以很容易地添加另一个设备,这只是就像一个现有的“除了......”。(您继承并覆盖更改的内容,有时可能会调用被覆盖的方法。)如果您保持命名和包装井井有条,您可以在代码增长时保持代码井井有条。

这一点很重要,因为即使处理器和图形协处理器的速度提高了,我们仍然无法在没有非常小心的情况下在我们所拥有的时间内绘制出我们需要的所有细节。

于 2013-08-28T18:38:33.730 回答
0

我认为您将模型对象与其抽屉分开的目标很重要。我将为抽屉创建一个单独的层次结构,它可以独立于模型而发展。所以我会有一个 PointDrawer 和一个 CircleDrawer 等'(可能都是从一些抽象的 EntityDrawer 扩展而来的。PointDrawer 可能是整个类层次结构的基础,这些类知道如何以各种方式(不同的颜色或不同的图形上下文)绘制一个点. 控制器应该获取模型对象和适当的抽屉。您可以使用工厂...控制器将用户动作/请求转换为模型动作/查询/逻辑(例如移动),然后参与适当的抽屉

于 2018-01-22T11:14:22.767 回答