1

我想在逻辑部分“数据”、“命令”和“引擎”中打破我的应用程序模型。应用程序之外的每个人都应该获得对数据的只读访问权和对命令的访问权。使用这些命令,他们可以操作数据。

其中,我在包中构建了我的应用程序:

myapp.model.data
myapp.model.commands
myapp.model.engines

引擎和命令都需要对数据进行写访问。因此,我必须以公共接口的形式公开写访问权限。这导致了外部客户端也对我的数据有写访问权限的问题,这是不允许的。这样做的问题是,命令使用事件调用引擎来检查数据的一致性。客户端将在不调用引擎的情况下操作数据,从而破坏数据的一致性。

这个问题有没有常见的做法。请不要建议我必须等到 Java 8,因为我现在想编写我的应用程序。将所有类都放在一个包中也是没有选择的,因为我会失去对应用程序的概述。

编辑

我阅读了一些关于树和图的不变性的网站。我看到了一个名为 zipper 的好主意:http: //scienceblogs.com/goodmath/2010/01/13/zippers-making-functional-upda/。不幸的是,这似乎不适用于我的情况。

回想一下,我有一个复杂的对象图结构,它将随着时间的推移进行操作。目标是限制客户端仅使用我的命令来操作数据。因此,在我的情况下,我没有看到不变性的优势。

为此,我为数据类提供了两个公共接口,一个是只读的,一个是可写的。每当客户端使用只读实例调用命令时,我只需将其强制转换为可写实例。这种方法解决了我的问题,但有两个很大的缺点。首先,我假设每个只读实例同时是一个可写实例——这可能会导致一些丑陋的错误。其次,客户端可以做同样的事情并具有写访问权限。但我不能说这是他们自己的错。

有人有更好的主意吗?

4

2 回答 2

1

我认为这是文件夹的常见限制(树状结构)。解决方案:

  1. 确保不应访问文档数据 (JavaDoc)。
  2. 如果你想走极端,你可以检查呼叫来自哪里并拒绝它(有点矫枉过正)

作为补充,这里有一篇关于这个主题的博客文章:一个从根本上改进你的包结构的简单建议

于 2013-02-27T09:54:53.060 回答
1

对于这类问题,我采用了三种模式。按照我尝试它们的大致顺序:

1)不可变/无副作用。函数式编程语言强烈推荐的一种技术,java.lang.String 就是一个例子。这里单个实例是不可变的,并且调用 mutate 创建一个新实例。可能不适用于您如何设计命令和引擎的接口,但如果您有精力重新设计他们的接口,那么这是一种非常强大的方法,可以减少行数。

2) 可锁定对象模式。一个对象在首次创建时是可变的,但在共享之前它是“锁定的”。在被锁定后,对变异方法的任何调用都会出错。解锁对象涉及创建对象的新副本。

3) 为可变实例创建一个只读包装器。这使您可以控制谁可以变异,以及谁可以只读。java.util.Collections#unmodifiableList(List list) 是这种装饰器样式模式的 Java 运行时示例,它将 setter 方法保留在共享接口上。可以使用完全没有 setter 方法的不同接口。

我的偏好始终是 1,因为它会导致更简单的代码更容易扩展。但是,如果我对此有疑问,那么我倾向于退回到 2,因为它在方法之间提供了平衡,并且不允许另一个线程正在改变另一个线程后面的实例的可能性。它也不需要那么多额外的代码,但它确实需要纪律来确保对象被正确锁定并强制执行锁定语义。因此,这在实践中并不是很常见的模式。

于 2013-02-27T09:56:55.510 回答