DDD—Repository倉儲&工廠模式


  一、解耦領域層和基礎層       
          DDD嚴格的分層架構告訴我們,每一層只能與其下方的一層發生耦合。因此用戶接口層只與應用層發生交互,應用層往下只與領域層發生交互,領域層往下只與基礎層發生交互。
    在傳統的代碼分層結構Controller—Service—Dao結構中,經常能看到在Service業務實現層的代碼中嵌入SQL,或者在其中頻繁出現修改數據對象並調用DAO的情況。這樣,基礎層的數據處理邏輯就滲透到了業務邏輯代碼中。
    在DDD的分層結構中,如果出現上述情況,則基礎層的數據處理邏輯就滲透到了領域層,領域層中的領域模型就難以聚焦在業務邏輯上,對外層的基礎層產生了依賴。而一旦涉及到數據邏輯的修改,就要到領域層中去修改代碼,重新調試領域層與基礎層的交互,或者當切換異構數據庫類型時,需要大量修改領域層的代碼,將業務邏輯和數據處理邏輯重新適配(主要在於異構數據庫導致的SQL或數據對象調整),因此技術升級會變得特別麻煩。
    本文要講的倉儲模式就是用來解耦領域層和基礎層的,降低他們之間的耦合和相互影響
    
 
  二、倉儲模式
        為了解耦領域邏輯和數據處理邏輯,在中間加了薄薄的一層倉儲。
    倉儲模式包含倉儲接口和倉儲實現,倉儲接口面向領域層提供基礎層數據處理相關的接口,倉儲實現則完成倉儲接口對應的數據持久化相關的邏輯處理。一個聚合配備一個倉儲,由倉儲完成聚合數據的持久化。領域層邏輯面向倉儲接口編程,聚合內的數據持久化過程為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;
}

 

     倉儲接口定義:
/**
 * 人員聚合倉儲接口
 * @author test11
 */
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;
    }
    
}

 

  

  參考書籍 ——《基於DDD和微服務的中台架構與實現》歐創新、鄧頔
  參考書籍 ——《領域驅動設計》Eric Evans
  參考書籍 ——《架構真經》Martin L. Abbott


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM