考虑使用DDD的系统(同样:使用ORM的任何系统)。实际上,在几乎每个用例中,任何系统的重点都是操纵这些域对象。否则,就没有真正的效果或目的。
修改一个不可变的对象会导致该对象持久化后生成新记录,这会在数据源中造成巨大的膨胀(除非您在修改后删除了以前的记录)。
我可以看到使用不可变对象的好处,但是从这个意义上讲,我从来没有看到使用不可变对象的有用案例。这是错的吗?
考虑使用DDD的系统(同样:使用ORM的任何系统)。实际上,在几乎每个用例中,任何系统的重点都是操纵这些域对象。否则,就没有真正的效果或目的。
修改一个不可变的对象会导致该对象持久化后生成新记录,这会在数据源中造成巨大的膨胀(除非您在修改后删除了以前的记录)。
我可以看到使用不可变对象的好处,但是从这个意义上讲,我从来没有看到使用不可变对象的有用案例。这是错的吗?
Answers:
使用不可变的对象进行计算(如在函数编程中一样)不一定意味着要持久化所生成的每个对象!
域中不可变是否意味着它必须在数据库中不可变?例如,考虑以下假设,假设客户始终有一个地址:
customer.address = new Address('My Castle', 'Kings street');
customer_repo.save(customer);
现在,运行以下sql,考虑到客户id为1:
INSERT INTO addresses (customer_id, name, street)
VALUES (1, 'My Castle', 'Kings street');
现在对地址进行以下更改:
customer.address = new Address('Pauper palace', 'Outlands');
customer_repo.save(customer);
持久层非常聪明,它运行以下sql:
UPDATE addresses SET name='Pauper palance', street='Outlands'
WHERE customer_id = 1;
这样,您可以避免单独的DELETE AND INSERT语句的开销。我也认为某些RDBMS具有INSERT REPLACE之类的功能。MySql有REPLACE。
在DDD中,不可变的对象几乎等同于值对象。这些对象不是实体,没有身份。因此,我总是将值对象持久化为它们所包含的实体的列(使用N / Hibernate,您可以使用组件)。他们没有自己的桌子。
这取决于不可变对象在数据库中的映射方式。如果它只是一个类似DateTime的组件(来自Joda Time库),则更改该值将导致更新而不是插入。但是,如果不可变变量更复杂,需要在表中一行,那么您就会遇到膨胀问题。
我想,尽管这是一个较弱的论点,但您可以通过这种方式实施审核跟踪。固定件的每次更改都可以通过插入件进行跟踪。尽管有许多更好的方法可以做到这一点。
总而言之,拥有不变的域对象(而不只是它们的组件)似乎与持久性有些不匹配。
这取决于域。DDD没有指定编程范例是面向对象的。但是,面向对象的范例非常适合必须保留在数据库中的典型应用程序。
DDD仅声明您应该围绕表示该软件试图解决的实际问题的域模型来构建软件。如果该问题本质上是数学的,那么使用功能编程和不可变数据结构实现域层将很有意义。
另一方面,如果问题更多是典型的企业应用程序,并且您对所有域对象都使用不可变的对象结构,那么我认为您没有遵循DDD。我可以提出至少两个参数:
您的实现不代表问题域的域模型。在这种情况下,您的问题域由状态需要修改的实体组成。那不是您实现它的方式。
您的语言并不普遍。域模型中的语言和概念不遵循域专家的使用。
注意:DDD确实在适当的地方使用不可变的对象,它们仅称为值对象。
因此,我并不是说您不能使用纯功能数据结构创建数据库应用程序,也不是说您不应这样做。我只是认为您不能将其称为DDD,具体取决于应用程序的类型