Java 限制公共可访问成员-解决方法

Java 限制公共可访问成员-解决方法,java,oop,visibility,Java,Oop,Visibility,我想在逻辑部分“数据”、“命令”和“引擎”中打破我的应用程序模型。应用程序之外的每个人都应该以只读方式访问数据和命令。通过这些命令,他们可以操纵数据 为此,我在软件包中构建了我的应用程序: myapp.model.data myapp.model.commands myapp.model.engines 引擎和命令都需要对数据进行写访问。因此,我必须以公共接口的形式公开写访问。这导致了一个问题,即外部客户端也可以对我的数据进行写访问,这是不允许的。这样做的问题是,命令使用事件调用引擎来检查数据

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

为此,我在软件包中构建了我的应用程序:

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

这个问题有共同的做法吗。请不要建议我必须等到Java8,因为我想现在就编写我的应用程序。将所有类放在一个包中也是没有选择的,因为我会丢失应用程序的概览

编辑

我浏览了一些关于树和图的不变性的网站。我看到了一个叫拉链的好主意。不幸的是,这似乎不适合我的情况

回想一下,我有一个复杂的对象图结构,它会随着时间的推移而被操纵。目标是限制客户端仅使用我的命令操作数据。因此,在我的案例中,我看不到不变性的优势

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


有人有更好的主意吗?

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

  • 确保不应访问文档数据(JavaDoc)
  • 如果你想走极端,你可以检查电话的来源并拒绝(有点过分)

  • 作为补充,这里有一篇关于这个主题的博文:

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

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

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

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


    我的首选项总是1,因为它会导致更简单的代码,更易于扩展。但是,如果我在这方面遇到问题,那么我倾向于使用2,因为它在两种方法之间提供了一个平衡,并且不允许另一个线程在另一个线程后面变异实例。它也不需要那么多额外的代码,但它确实需要规程来确保对象被正确锁定并强制执行锁定语义。因此,这在实践中不是一种非常常见的模式。

    我喜欢不可变类的想法。这里的问题是,我的数据是树状结构的,并且充当UI的数据源。我将对此进行调查,并尝试找到一个好的解决方案。谢谢你的回答。重新设计不可变的数据结构可能很棘手。Clojure使用了一种模式,该模式由一个hash-trie支持,可用于您的案例。它涉及使用不可变的哈希映射来实现树。也许对你来说太过分了,但这是一本有趣的书。在这里,不变性的优势是什么。我的数据会随着时间的推移而变化,因此不是一成不变的。这是可能的,但我所追求的是一个解决方案,外部世界只能通过命令来操纵数据。我想你已经知道可能的解决方案,请阅读以下内容: