在绘图应用程序中分离模型和视图/控制器

Las*_*rte 13 java oop model-view-controller user-interface vector-graphics

我正在使用矢量绘图应用程序(在java中),我正在努力解决我的模型类和视图/控制器类之间的分离.

一些背景:

您可以绘制不同的形状:
矩形,线条和饼图段

有4种工具可以在画布上操纵形状:
缩放工具,移动工具,旋转工具和变形工具

对于这个问题,变形工具是最有趣的一个:它允许您通过拖动其中一个点并调整其他属性来更改形状,如下图所示:

操纵形状的不同选项

这些转换规则对于每个形状都是不同的,我认为它们是模型业务逻辑的一部分,但在某种程度上它们需要暴露给视图/控制器(工具类),以便它们可以应用正确的形状.

此外,形状通过不同的值在内部表示: - 矩形存储为中心,宽度,高度,旋转 - 该行存储为起点和终点 - 饼图段存储为中心,半径,角度1,角度2

我计划在未来添加更多形状,如星星,气泡或箭头,每个都有自己的控制点.

我还计划在未来添加更多工具,例如旋转或缩放形状组.

每个工具的控制点都不同.例如,使用缩放工具时,您无法抓取中心点,但每个缩放控制点需要与一个轴点(或多个让用户选择)相关联.

对于像矩形,直线和饼图这样的简单形状,控制点对于类的每个实例都是相同的,但是期货形状如贝塞尔曲线路径或星形(具有可配置的尖峰数)将为每个实例提供不同数量的控制点.

那么问题是什么是建模和实施这些控制点的好方法?

由于它们对于每个工具略有不同并且携带一些工具/控制器特定数据,因此它们以某种方式属于工具/控制器.但由于它们也特定于每种类型的形状并且具有非常重要的域逻辑,因此它们也属于该模型.

我想避免在添加一个工具或形状时为每个工具/形状组合添加特殊类型的控制点的组合爆炸.


更新:再举一个例子:将来我可能会想到一个我想要支持的新形状:弧形.它类似于饼段,但看起来有点不同,拖动控制点时表现完全不同.

为了实现这一点,我希望能够创建一个实现我的Shape接口的ArcShape类并完成.

弧形的行为

bag*_*rat 8

基本考虑因素

首先,让我们为简单起见做一些定义.

Entity是一个域模型对象,它定义了所有的结构和行为,即逻辑. EntityUI是表示EntityUI中的图形控件.

所以基本上,对于Shape类,我认为ShapeUI必须非常了解它的结构Shape.结构主要由我猜测的控制点组成.换句话说,拥有关于控制点的所有信息(可能是将来的矢量),ShapeUI将能够在UI上绘制自己.

初步建议

我建议的Shape类是,Shape类定义了所有的行为.该ShapeUI班会意识到Shape类,并保持一个它是代表一个参考,通过它可以访问控制点,以及能够操纵它们,例如设置自己的位置.该Observer模式只是要求在这种情况下使用.特别地,Shape该类可以实现Observable并且ShapeUI将实现Observer和订阅相应的Shape对象.

基本上在这种情况下会发生什么,该ShapeUI对象将处理所有UI操作,并将负责更新Shape参数,例如控制点位置.之后,一旦发生位置更新,Shape对象就在状态改变时执行其逻辑,然后盲目地(不知道ShapeUI)通知ShapeUI关于更新的状态.因此相应地ShapeUI将绘制新的状态.在这里,您将获得低耦合模型和视图.

至于Tools我自己的观点是,每个人都Tool必须知道如何操纵每种类型Shape,即每个形状操纵逻辑必须在Tool类中实现.对于解耦视图和模型,它几乎与Shape.的ToolUI类处理光标点击其中,什么ShapeUI是它点击,什么控制点是它点击等通过获得该信息,ToolUI将其传递给适当的Tool对象,然后将应用基于所接收的参数的逻辑.

处理不同的形状类型

现在,当谈到以自己的方式Tool处理不同的Shapes时,我认为Abstract Factory模式介入.每个工具将实现Abstract Factory我们将为每种类型提供操作实现的位置Shape.

摘要

根据我的建议,这里是领域模型草案:

领域模型

为了从我的建议中得到完整的想法,我还发布了特定用例的序列图:

使用ToolUI用户点击ShapeUI'sControlPointUI

在此输入图像描述


Tyl*_*den 1

原则上,让模型与绘图界面相匹配是一个好主意。因此,例如,在 Java Swing 中,可以使用以左上角的、 、宽度和高度drawRect作为参数的方法来绘制矩形。因此,通常您希望将矩形建模为xy{ x-UL, y-UL, width, height }

对于任意路径(包括圆弧),Swing 为GeneralPath对象提供了处理通过直线或二次/贝塞尔曲线连接的点序列的方法。要对 GeneralPath 进行建模,您可以提供点列表、缠绕规则以及二次曲线或贝塞尔曲线的必要参数。