5

我想在一个小型绘画应用程序中实现撤消/重做。似乎命令模式非常适合使用,但我不确定如何最好地实现它。

据我了解该模式,有必要在每个命令中包含:

  1. 用于重做的绘制操作的详细信息(例如 Line -> start & end points, free form line -> GeneralPath
  2. 撤消更改之前组件的状态。在这种情况下,这将是受命令影响的区域的小快照图像。

我基于此的理解是,每个命令都需要是“原子的”或自包含的,以及撤消/重做该操作所需的所有信息。

不幸的是,这需要存储比我最初预期的更多的信息。对于一条线,我们还必须考虑Color,StrokeRenderingHints最初用来绘制它的东西。这将我的“简单的小命令”变成了……在内存中更庞大的东西,并产生了更多的样板代码(每个都是可序列化的 bean 1)。

出于节省内存的原因(主要是),我想在命令规范上“作弊”。可能每 100 次更新备份整个绘图区域,否则不存储更改的图像的任何部分,并且只需为每个新的绘制操作重建最后(最多)100 个命令。但是,在绘制每个部分之前确保Graphics对象的状态正确似乎是有问题的 - 这部分可能需要一行,但是RenderingHints4 个命令前已Color更改, 98 个命令前已更改,而Stroke最后一个保持不变227 个命令。

就“原子”而言,追求更高效的内存命令似乎会将模式扔出窗外。这反过来又导致难以确定可能影响渲染的最早命令。

我是不是该:

  • 寻找新模式?
  • 尝试通过调整模式来实现我的特殊需求?
  • 将所有这些作为过早的优化扔进垃圾箱,并以最简单(也是最消耗内存)的方式进行编码,并按照定义的命令模式进行编码?

更新

  1. “每个都将是一个可序列化的bean” 第二个想法,不。我做了圆顶检查,发现 a Graphics2D(它巧妙地封装了绘图时使用的许多参数)不可序列化。此外,aBasicStroke 是可序列化的,但笔画的粗细不被存储。我可以创建许多属性的可序列化版本,但它似乎需要更多代码,所以我将放弃该规范。也是。我只会尝试BufferedImage在运行时存储对 a 的引用。
4

2 回答 2

3

我会坚持使用命令模式并首先尝试一个幼稚的解决方案(=最需要内存的)。对于某些图形操作,甚至可能需要在命令对象中保留整个图像的副本(例如,考虑过滤器)。这也是专业图像编辑应用程序中的常见问题,它们通常对记住的最后命令有内存或步数限制。如果内存消耗非常大,您可能会考虑将命令历史记录中最旧的条目交换到文件系统。我认为用户不会介意等待一秒钟,直到更改撤消。

于 2012-10-08T10:52:42.357 回答
1

也许,最好不要在命令中存储整个图像的副本,而只存储由命令更改的区域的副本。当然,这不是灵丹妙药

于 2012-10-08T11:32:37.313 回答