用于将模型与其图形表示分离的设计模式

时间:2013-08-28 18:08:23

标签: java oop design-patterns code-separation

问题

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

我有一组表示属于2D笛卡尔平面的各种实体,例如PointVectorArc等,由类{{Model表示。 1}}。 Model类充当这些实体的集合,并存储有用的计算值。

我还有一个可视化界面,它应该呈现模型状态的2D图像,并且还可以通过向模型添加实体来在很小程度上与模型交互(例如,用户可以添加{{ 1}}通过点击某处的GUI来模型。)。

第一个想法

首先,我有一个接口Point,它有一个接受图形上下文对象的方法Drawable,并且实现实体将使用我的图形库将自己绘制到该上下文使用(在这种情况下为Java Swing / AWT)。

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

第二个想法

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

这种方法实现了我正在寻找的代码分离,但EntityDrawer类严重依赖于EntityDrawer / instanceOf方法来确定如何绘制实体,我有反复看到被描述为糟糕的设计。我尝试重新设计这个,以便类使用重载方法来确定使用哪种绘图方法,但我意识到这基本上是以更好看的方式编写的isA / instanceOf方法。另外,对于我添加的每个新实体类,我需要在这个isA的代码中反映出来,这感觉就像是与我耦合的一种形式。


我希望尽可能多地将模型与其图形表示分离,以便模型可以专注于对问题进行建模,而不是如何将自身渲染到图形上下文。此外,我将来可能会添加更多模型实体类型,这些类型将具有截然不同的绘图需求。

那么,我可以使用一种模式或设计技术来实现这一目标吗?我觉得我提出的两个解决方案是次优的,并且可能存在一种设计模式,可以完全解决这类问题。

4 个答案:

答案 0 :(得分:2)

在我看来,你错过了模型,视图,控制器(或MVC)设计模式的Controller部分。

控制器将与模型通信并与视图(图形部分)通信,从而使视图和模型彼此独立。

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

答案 1 :(得分:0)

答案 2 :(得分:0)

在过去,我们曾经在一个绘图抽象层的顶部构建所有这些,界面非常简单:在点x,y处放置一个颜色点c。

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

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

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

对于每个新的可绘制对象,Circle,Arc,Ellipse,Box,FilledBox等,内部有一个相应的XxxDrawer,它使用三个层次的组合来绘制图形。

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

这非常令人困惑,但它确实允许绘制每个东西以获得最大性能(如果做动画很有用,你需要每秒24个图像,但图像中有1000个弧)加上它可以很容易地添加另一个设备就像现有的“除了...”。 (你子类化并覆盖已更改的东西,有时可能会调用overriden方法。)如果你保持命名和打包的组织,你可以随着代码的增长保持代码的组织。

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

答案 3 :(得分:0)

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