我将不可变数据模型类标记为final
确保更改其值的唯一方法是创建一个新实例。 (不幸的是,这些字段不能是最终的,因为它们需要由 Hibernate 填充。)
这工作得很好,直到我想检查另一个类在使用模型的无效实例调用时是否抛出正确的异常。模型的构造函数会验证参数,因此必须使用反射来设置字段。这是非常笨拙的,因为模型有相当多的字段,并且字段名称必须进行硬编码。
我也不能嘲笑该模型,因为它是最终的。 (是否应该使用接口来启用模拟,同时保持类不可变,是否也存在争议。通过使用接口,就无法以编程方式强制方法在实例的整个生命周期中必须返回相同的值。)
在这种情况下人们通常会做什么?有没有任何标准方法?
一般来说,您不应该想要模拟数据对象。数据对象应该没有逻辑,也没有外部依赖关系,因此模拟对象并没有多大用处。相反,可以非常轻松地创建假实例,您可以根据需要将其填充到方法中。
此外,还有一些其他原因您可能希望避免将 Hibernate 持久对象视为不可变:
- Hibernate 提供的对象本质上是不是线程安全的 https://developer.atlassian.com/display/CONFDEV/Hibernate+Sessions+and+Transaction+Management+Guidelines#HibernateSessionsandTransactionManagementGuidelines-Multi-threading因此失去了不可变值对象通常提供的线程安全优势。
- 你可能会发现你的对象实际上是proxies https://stackoverflow.com/questions/2594804/why-is-hibernate-returning-a-proxy-object,可能会削弱
final
语义。
- Hibernate 控制的对象的操作方式完全不同他们的会议是否仍然开放 http://docs.jboss.org/hibernate/orm/3.6/javadocs/org/hibernate/Session.html(附加与分离)使它们成为不可变对象的非常糟糕的选择。如果您的不可变对象取决于会话生存期,那么它并不是真正不可变的。
- 听起来有些对象在应用程序层可能有效或无效,超出了数据库层验证。这使得封装您的验证问题变得有点困难。
- 您需要有一个公共的无参数构造函数,这与不可变值对象典型的实例控制类型相反。
- 由于对象本质上是可变的,因此更复杂覆盖 equals 和 hashCode https://stackoverflow.com/a/1638886/1426891.
我的建议?如果您需要比 Hibernate DAO 所能提供的更多的不变性和数据验证保证,那么创建一个real具有最终字段(或私有构造函数和静态工厂方法)的最终不可变类,然后创建一个从 Hibernate DAO 复制值的构造函数(或静态工厂方法)。
如果您决定此选项,您将面临以下开销:two大致并行更改的数据对象,但您还可以获得分离关注点的好处(以防 Hibernate 对象出现分歧)以及真正不可变、等于和哈希码覆盖、会话不可知、保证有效的易用性您可以轻松创建用于测试的对象。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)