如何正确映射持久层和域对象

Sir*_*eta 5 java domain-driven-design

假设我有一个代表一个人的域 java 类:

class Person {

    private final String id; // government id
    private String name;
    private String status;

    private Person(String id, String name) {
        this.id = id;
        this.name = name;
        this.status = "NEW";
    }

    Person static createNew(String id, String name) {
        return new Person(id, name);
    }

    void validate() {
        //logic
        this.status = "VALID";
    }


    public static final class Builder {

        private String id;
        private String name;
        private String status;

        private Builder() {
        }

        public static Builder aPerson() {
            return new Builder();
        }

        public Builder id(String id) {
            this.id = id;
            return this;
        }

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder status(String status) {
            this.status = status;
            return this;
        }

        public Person build() {
            Person person = new Person(id, name);
            person.status = this.status;
            return person;
        }
    }
Run Code Online (Sandbox Code Playgroud)

我将此域类对象存储在数据库中,具有相同字段 + getter 和 setter 的常规类。目前,当我想存储对象时,我创建了新对象PersonDocument(数据存储在 mongo 中),使用 getter 和 setter 并保存它。当我想从数据库中获取它时,它变得很复杂。我希望我的域对象只公开必要的内容,对于目前的业务逻辑,它只是创建和验证。简单地:

Person p = Person.createNew("1234", "John");
p.validate();
repository.save(p); 
Run Code Online (Sandbox Code Playgroud)

另一方面它变得复杂,目前有一个构建器允许在任何状态下创建对象。我们确实相信存储在 DB 中的数据具有适当的状态,因此可以通过这种方式创建,但缺点是有一个公共 API 可用,让任何人都可以做任何事情。

最初的想法是使用 MapStruct java 映射库,但它确实使用 setter 来创建对象,并且应该避免在域类中公开 setter(据我所知)。

任何建议如何正确地做到这一点?

Rob*_*gam 2

您的问题可能来自两个相互冲突的要求:

  1. 您只想公开业务方法。
  2. 您也希望公开数据,因为您希望能够在对象外部实现序列化/反序列化。

其中之一必须给予。老实说,大多数面临这个问题的人都会忽略第一个问题,而只是引入 setter/getter。另一种选择当然是忽略第二个,只将序列化/反序列化引入对象中。

例如,您可以在生成 Mongo 兼容 json 文档的Document toDocument() 对象中引入一个方法,也可以引入一个Person fromDocument(Document)反序列化方法。

大多数人不喜欢这种解决方案,因为它将技术与对象“耦合”。这是好事还是坏事?取决于您的用例。您想针对哪一项进行优化:改变业务逻辑还是改变技术?如果您不打算经常更改技术,也不打算在完全不同的应用程序中使用相同的类,则没有理由分离技术。