DDD之仓储模式和工厂模式

王大爷 2022年05月02日 724次浏览

仓储模式

为了解耦领域逻辑和数据处理逻辑,在中间加了薄薄的一层仓储。

    仓储模式包含仓储接口和仓储实现,仓储接口面向领域层提供基础层数据处理相关的接口,仓储实现则完成仓储接口对应的数据持久化相关的逻辑处理。一个聚合配备一个仓储,由仓储完成聚合数据的持久化。领域层逻辑面向仓储接口编程,聚合内的数据持久化过程为DO(领域对象)转PO(持久化对象)。

    当需要更换数据库类型,或者更改数据处理逻辑时,我们就可以保持业务逻辑接口不动,只修改仓储实现,保证了领域层业务逻辑的干净和纯洁。

    如下示例为一个人员聚合中对人员实体的仓储模式实现:

    人员DO和人员PO定义:  

/** \* 人员聚合
 \* @author test11
 \*/
public class Person {

    //人员id
    private String id;

    //姓名
    private String name;

    //地址(值对象)
    private Address address;

    //上班行为
    private void goWork(){

    }

    //下班行为
    private void leaveWork(){

    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}
/** \* 人员聚合的持久化PO
 \* @author test11
 \*/
public class PersonPO {

    //人员id
    private String id;

    //姓名
    private String name;

    //地址
    private Address address;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}
/** \* 地址值对象
 \*/
public class Address {

    //省份
    private String province;
    //城市
    private String city;
    //街道
    private String street;
}

复制代码

    仓储接口定义:

复制代码

/** \* 人员聚合仓储接口
 \*/
public interface PersonRepository {

    /**     \* 添加人员
     \*/
    void addPerson(PersonPO personPO);

    /**     \* 更新人员
     \*/
    void updatePerson(PersonPO personPO);

    /**     \* 根据id查找人员PO对象
     \* @return
     \*/    PersonPO findById(String id);
}

仓储接口实现:

/** \* 人员仓储实现
 \* @author test11
 \*/
public class PersonRepositoryImpl implements PersonRepository{

    @Resource
    PersonDao personDao;

    @Override
    public void addPerson(PersonPO personPO) {
        personDao.addPerson(personPO);
    }

    @Override
    public void updatePerson(PersonPO personPO) {
        personDao.updatePerson(personPO);
    }

    @Override
    public PersonPO findById(String id) {
        return personDao.findById(id);
    }
}

人员领域服务实现:后面基础层发生了变化,则领域层无需动任何代码,只要仓储接口不变,领域层的逻辑就可以一直保持不变,维护了领域层的稳定性。领域服务是可以做成企业级可复用的服务的,因此稳定性必须有保障。**

import javax.annotation.Resource;/** \* 人员领域服务聚合类
 \* @author test11
 \*/
public class PersonDomainService {

    @Resource
    PersonRepository personRepository;

    public void addPerson(PersonPO personPO) {
        personRepository.addPerson(personPO);
    }
}

工厂模式

DO对象创建时,需要确保聚合根和它依赖的对象同时被创建,如果这项工作交给聚合根来实现,则聚合根的构造函数将变得异常庞大,所以我们把通用的初始化DO的逻辑,放到工厂中去实现,通过工厂模式封装聚合内复杂对象的创建过程,完成聚合根,实体和值对象的创建。DO对象创建时,通过仓储从数据库中获取PO对象,通过工厂完成PO到DO的转换

工厂中还可以包含DO到PO对象的转换过程,方便完成数据的持久化。

/** \* Person聚合的工厂
 \* DO和PO的转换
 \* @author test11
 \*/
public class PersonFactory {

    /**     \* 人员PO到领域对象的数据初始化
     \* @param personPO
     \* @return
     \*/
    protected Person createPerson(PersonPO personPO){
        Person person = new Person();
        person.setId(personPO.getId());
        person.setName(personPO.getName());
        person.setAddress(personPO.getAddress());
        return person;
    }

    /**     \* 领域对象到持久化对象PO的转换
     \* @param person
     \* @return
     \*/
    protected PersonPO createPersonPO(Person person){
        PersonPO personPO = new PersonPO();
        personPO.setId(person.getId());
        personPO.setName(person.getName());
        personPO.setAddress(person.getAddress());
        return personPO;
    }

}