java中的DDD思想指的是什么及在Java中的體現(xiàn)詳解
前言
Java 中的 DDD 指的是 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(Domain-Driven Design),它是一種軟件開(kāi)發(fā)方法論,強(qiáng)調(diào)以業(yè)務(wù)領(lǐng)域?yàn)楹诵?/strong>來(lái)設(shè)計(jì)和構(gòu)建復(fù)雜系統(tǒng)。DDD 并不是一種框架或技術(shù),而是一種設(shè)計(jì)思想和架構(gòu)理念,特別適用于業(yè)務(wù)邏輯復(fù)雜、核心領(lǐng)域價(jià)值高的系統(tǒng)(如金融、電商、ERP 等)。
什么是 DDD(Domain-Driven Design)?
“把軟件的焦點(diǎn)放在核心領(lǐng)域和領(lǐng)域邏輯上,通過(guò)與領(lǐng)域?qū)<业拿芮泻献鳎粩嗵釤挸鲱I(lǐng)域模型。”
—— Eric Evans(DDD 之父,《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》作者)
核心思想:
- 軟件系統(tǒng)的核心是業(yè)務(wù)領(lǐng)域(Domain),而不是技術(shù)細(xì)節(jié)(如數(shù)據(jù)庫(kù)、框架)。
- 開(kāi)發(fā)者應(yīng)與領(lǐng)域?qū)<?/strong>(業(yè)務(wù)人員)緊密協(xié)作,建立統(tǒng)一的“通用語(yǔ)言”(Ubiquitous Language)。
- 通過(guò)建模將復(fù)雜的業(yè)務(wù)邏輯轉(zhuǎn)化為清晰的代碼結(jié)構(gòu)。
DDD 的三大核心概念
| 概念 | 說(shuō)明 |
|---|---|
| ? 領(lǐng)域(Domain) | 軟件所要解決的現(xiàn)實(shí)世界問(wèn)題范圍,如“電商”、“銀行信貸”、“物流”等。 |
| ? 模型(Model) | 對(duì)領(lǐng)域內(nèi)關(guān)鍵概念和規(guī)則的抽象,通常體現(xiàn)為代碼中的類(lèi)、方法、關(guān)系。 |
| ? 設(shè)計(jì)(Design) | 如何組織代碼結(jié)構(gòu),使模型在代碼中清晰體現(xiàn),便于維護(hù)和擴(kuò)展。 |
DDD 的分層架構(gòu)(經(jīng)典四層)
+---------------------+ | 用戶接口層(UI Layer) | ← HTTP、Web、RPC 接口 +---------------------+ | 應(yīng)用層(Application Layer) | ← 用例協(xié)調(diào)、事務(wù)控制 +---------------------+ | 領(lǐng)域?qū)樱―omain Layer) | ← 核心業(yè)務(wù)邏輯、實(shí)體、聚合、領(lǐng)域服務(wù) +---------------------+ | 基礎(chǔ)設(shè)施層(Infrastructure Layer)| ← 數(shù)據(jù)庫(kù)、消息、外部服務(wù)調(diào)用 +---------------------+
?? 依賴方向:上層依賴下層,但 DDD 推薦使用依賴倒置(如通過(guò)接口解耦)。
DDD 核心戰(zhàn)術(shù)模式(戰(zhàn)術(shù)設(shè)計(jì))
這些是 DDD 中用于建模的具體“工具”:
| 概念 | 說(shuō)明 |
|---|---|
| ? 實(shí)體(Entity) | 有唯一標(biāo)識(shí)的對(duì)象,生命周期中狀態(tài)會(huì)變化。<br>如:User、Order,用 id 區(qū)分。 |
| ? 值對(duì)象(Value Object) | 無(wú)唯一標(biāo)識(shí),只表示值或?qū)傩越M合。<br>如:Money、Address,通過(guò)屬性判斷相等。 |
| ? 聚合(Aggregate) | 一組關(guān)聯(lián)對(duì)象的集合,有一個(gè)**聚合根(Aggregate Root)**作為入口。<br>如:Order 是聚合根,包含 OrderItem。 |
| ? 領(lǐng)域服務(wù)(Domain Service) | 處理跨多個(gè)實(shí)體的業(yè)務(wù)邏輯,本身無(wú)狀態(tài)。<br>如:TransferService 轉(zhuǎn)賬服務(wù)。 |
| ? 工廠(Factory) | 封裝復(fù)雜對(duì)象的創(chuàng)建邏輯。 |
| ? 倉(cāng)儲(chǔ)(Repository) | 提供聚合的持久化訪問(wèn)接口,屏蔽數(shù)據(jù)庫(kù)細(xì)節(jié)。<br>如:OrderRepository。 |
| ? 領(lǐng)域事件(Domain Event) | 表示領(lǐng)域中發(fā)生的事件,用于解耦。<br>如:OrderCreatedEvent。 |
示例:電商訂單系統(tǒng)(Java 代碼片段)
// 值對(duì)象:金額
public class Money {
private BigDecimal amount;
private String currency;
public Money(BigDecimal amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public Money add(Money other) {
if (!this.currency.equals(other.currency)) throw new IllegalArgumentException();
return new Money(this.amount.add(other.amount), currency);
}
}
// 實(shí)體:訂單項(xiàng)
public class OrderItem {
private Long id;
private String productName;
private Money price;
private int quantity;
}
// 聚合根:訂單
public class Order {
private Long id;
private List<OrderItem> items = new ArrayList<>();
private Money total;
private String status;
public void addItem(OrderItem item) {
this.items.add(item);
this.total = this.total.add(item.getPrice().multiply(item.getQuantity()));
}
public void confirm() {
if (this.status.equals("CREATED")) {
this.status = "CONFIRMED";
// 發(fā)布領(lǐng)域事件
DomainEventPublisher.publish(new OrderConfirmedEvent(this.id));
}
}
}
// 領(lǐng)域服務(wù)
@Service
public class OrderService {
public void cancelOrder(Order order) {
// 復(fù)雜業(yè)務(wù)邏輯
if (order.isCancelable()) {
order.setStatus("CANCELLED");
orderRepository.save(order);
}
}
}DDD 的優(yōu)勢(shì)
| 優(yōu)點(diǎn) | 說(shuō)明 |
|---|---|
| ? 業(yè)務(wù)與代碼高度一致 | 模型直接反映業(yè)務(wù),便于溝通和維護(hù)。 |
| ? 高內(nèi)聚、低耦合 | 聚合、領(lǐng)域服務(wù)等設(shè)計(jì)提升可維護(hù)性。 |
| ? 易于應(yīng)對(duì)復(fù)雜業(yè)務(wù) | 適合核心領(lǐng)域復(fù)雜的系統(tǒng)。 |
| ? 支持微服務(wù)拆分 | 每個(gè)“限界上下文”可對(duì)應(yīng)一個(gè)微服務(wù)。 |
DDD 的適用場(chǎng)景
| 適合 | 不適合 |
|---|---|
| 業(yè)務(wù)復(fù)雜、核心邏輯多 | CRUD 簡(jiǎn)單系統(tǒng)(如后臺(tái)管理) |
| 需要長(zhǎng)期演進(jìn) | 短期項(xiàng)目、原型開(kāi)發(fā) |
| 有領(lǐng)域?qū)<覅⑴c | 團(tuán)隊(duì)缺乏業(yè)務(wù)理解 |
| 微服務(wù)架構(gòu) | 小型單體應(yīng)用 |
DDD 與傳統(tǒng)三層架構(gòu)對(duì)比
| 維度 | 傳統(tǒng)三層架構(gòu) | DDD 架構(gòu) |
|---|---|---|
| 關(guān)注點(diǎn) | 技術(shù)分層(Controller/Service/DAO) | 業(yè)務(wù)領(lǐng)域建模 |
| 業(yè)務(wù)邏輯位置 | 多在 Service 層(貧血模型) | 在領(lǐng)域?qū)ο髢?nèi)部(充血模型) |
| 可維護(hù)性 | 復(fù)雜業(yè)務(wù)易混亂 | 更清晰、可擴(kuò)展 |
| 學(xué)習(xí)成本 | 低 | 較高 |
總結(jié)
DDD 是一種“以業(yè)務(wù)為中心”的軟件設(shè)計(jì)思想,它通過(guò):
- 建立通用語(yǔ)言
- 提煉領(lǐng)域模型
- 使用聚合、實(shí)體、值對(duì)象、領(lǐng)域服務(wù)等模式
- 構(gòu)建清晰、可維護(hù)、可擴(kuò)展的系統(tǒng)
簡(jiǎn)單一句話:
不要只寫(xiě) CRUD,要學(xué)會(huì)用代碼表達(dá)業(yè)務(wù)!
推薦學(xué)習(xí)
- 書(shū)籍:《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì):軟件核心復(fù)雜性應(yīng)對(duì)之道》—— Eric Evans
- 框架支持:Spring Boot + JPA 可很好地實(shí)現(xiàn) DDD 分層
- 擴(kuò)展:CQRS、事件溯源(Event Sourcing)、六邊形架構(gòu)(Hexagonal Architecture)
DDD 是中高級(jí) Java 工程師必備的設(shè)計(jì)能力,掌握后能顯著提升系統(tǒng)設(shè)計(jì)水平。
DDD(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì))是一種軟件設(shè)計(jì)方法論,Java中的DDD思想指的是將領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的核心理念和實(shí)踐應(yīng)用于Java項(xiàng)目開(kāi)發(fā)中。
DDD的核心思想
1. 關(guān)注領(lǐng)域模型
核心目標(biāo):將業(yè)務(wù)邏輯集中在領(lǐng)域模型中,而不是分散在各個(gè)技術(shù)層中。
java
// 傳統(tǒng)貧血模型 vs DDD充血模型
// ? 貧血模型(不推薦)
public class Order {
private Long id;
private BigDecimal amount;
// 只有g(shù)etter/setter
}
public class OrderService {
public void calculateDiscount(Order order) {
// 業(yè)務(wù)邏輯在Service中
}
}
// ? DDD充血模型(推薦)
public class Order {
private Long id;
private BigDecimal amount;
private List<OrderItem> items;
// 業(yè)務(wù)邏輯在領(lǐng)域?qū)ο笾?
public BigDecimal calculateDiscount() {
// 折扣計(jì)算邏輯
return this.amount.multiply(getDiscountRate());
}
private BigDecimal getDiscountRate() {
// 領(lǐng)域規(guī)則
if (amount.compareTo(new BigDecimal("1000")) > 0) {
return new BigDecimal("0.9");
}
return BigDecimal.ONE;
}
}DDD的核心概念在Java中的體現(xiàn)
1. 分層架構(gòu)
java
// 典型DDD分層結(jié)構(gòu) ├── application/ // 應(yīng)用層 - 用例協(xié)調(diào) ├── domain/ // 領(lǐng)域?qū)?- 業(yè)務(wù)核心 ├── infrastructure/ // 基礎(chǔ)設(shè)施層 - 技術(shù)實(shí)現(xiàn) └── interfaces/ // 接口層 - 對(duì)外暴露
2. 實(shí)體(Entity)
java
public class Order implements Entity<Order> {
private OrderId id; // 值對(duì)象作為標(biāo)識(shí)
private Money totalAmount;
private OrderStatus status;
// 通過(guò)標(biāo)識(shí)判斷相等性
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Order order = (Order) obj;
return id.equals(order.id);
}
// 業(yè)務(wù)方法
public void cancel() {
if (!status.canCancel()) {
throw new IllegalStateException("訂單無(wú)法取消");
}
this.status = OrderStatus.CANCELLED;
}
}3. 值對(duì)象(Value Object)
java
public class Money implements ValueObject {
private final BigDecimal amount;
private final Currency currency;
public Money(BigDecimal amount, Currency currency) {
this.amount = amount;
this.currency = currency;
}
// 值對(duì)象基于所有屬性判斷相等性
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Money money = (Money) obj;
return amount.compareTo(money.amount) == 0 &&
currency.equals(money.currency);
}
// 不可變操作
public Money add(Money other) {
if (!currency.equals(other.currency)) {
throw new IllegalArgumentException("貨幣類(lèi)型不匹配");
}
return new Money(amount.add(other.amount), currency);
}
}4. 聚合根(Aggregate Root)
java
public class Order implements AggregateRoot {
private OrderId id;
private List<OrderItem> items; // 內(nèi)部實(shí)體
private CustomerId customerId;
// 聚合根負(fù)責(zé)維護(hù)完整性
public void addItem(Product product, int quantity) {
if (quantity <= 0) {
throw new IllegalArgumentException("數(shù)量必須大于0");
}
OrderItem newItem = new OrderItem(product.getId(), quantity, product.getPrice());
items.add(newItem);
recalculateTotal();
}
// 外部只能通過(guò)聚合根訪問(wèn)內(nèi)部對(duì)象
public List<OrderItem> getItems() {
return Collections.unmodifiableList(items);
}
}5. 領(lǐng)域服務(wù)(Domain Service)
java
public class OrderCalculationService {
// 處理不適合放在實(shí)體中的跨聚合業(yè)務(wù)邏輯
public Discount calculateBestDiscount(Order order, Customer customer, List<Promotion> promotions) {
// 復(fù)雜的折扣計(jì)算邏輯
return promotions.stream()
.filter(p -> p.isApplicable(order, customer))
.map(p -> p.calculateDiscount(order))
.max(Comparator.comparing(Discount::getAmount))
.orElse(Discount.NONE);
}
}6. 倉(cāng)儲(chǔ)接口(Repository)
java
// 領(lǐng)域?qū)佣x接口
public interface OrderRepository {
Order findById(OrderId id);
void save(Order order);
List<Order> findByCustomerId(CustomerId customerId);
}
// 基礎(chǔ)設(shè)施層實(shí)現(xiàn)
@Repository
public class OrderRepositoryImpl implements OrderRepository {
@Autowired
private OrderJpaRepository jpaRepository;
@Override
public Order findById(OrderId id) {
OrderEntity entity = jpaRepository.findById(id.getValue())
.orElseThrow(() -> new OrderNotFoundException(id));
return orderMapper.toDomain(entity);
}
}Java中實(shí)現(xiàn)DDD的最佳實(shí)踐
1. 包結(jié)構(gòu)組織
java
com.example.ordermanagement
├── application
│ ├── command
│ ├── query
│ └── service
├── domain
│ ├── model
│ ├── service
│ ├── repository
│ └── exception
├── infrastructure
│ ├── persistence
│ ├── external
│ └── config
└── interfaces
├── rest
├── dto
└── mapper2. 使用特定注解標(biāo)記
java
// 自定義注解明確DDD角色
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DomainEntity {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DomainService {
}
@DomainEntity
public class Order {
// 領(lǐng)域?qū)嶓w
}
@DomainService
public class OrderValidationService {
// 領(lǐng)域服務(wù)
}DDD在Java項(xiàng)目中的優(yōu)勢(shì)
業(yè)務(wù)復(fù)雜度管理:將復(fù)雜業(yè)務(wù)邏輯封裝在領(lǐng)域模型中
代碼可維護(hù)性:清晰的架構(gòu)分層和職責(zé)分離
團(tuán)隊(duì)協(xié)作:統(tǒng)一的語(yǔ)言(Ubiquitous Language)
技術(shù)無(wú)關(guān)性:領(lǐng)域?qū)硬灰蕾嚲唧w技術(shù)實(shí)現(xiàn)
測(cè)試友好:領(lǐng)域?qū)ο罂梢元?dú)立測(cè)試
DDD特別適合業(yè)務(wù)復(fù)雜、需要長(zhǎng)期維護(hù)的Java企業(yè)級(jí)應(yīng)用,能夠有效應(yīng)對(duì)業(yè)務(wù)變化和技術(shù)演進(jìn)。
到此這篇關(guān)于java中的DDD思想指的是什么及在Java中體現(xiàn)的文章就介紹到這了,更多相關(guān)java中DDD思想和體現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)聯(lián)機(jī)五子棋
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)聯(lián)機(jī)五子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
spring的xml文件打開(kāi)沒(méi)有namespace等操作選項(xiàng)的解決方案
這篇文章主要介紹了spring的xml文件打開(kāi)沒(méi)有namespace等操作選項(xiàng)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Springboot集成RabbitMQ死信隊(duì)列的實(shí)現(xiàn)
在大多數(shù)的MQ中間件中,都有死信隊(duì)列的概念。本文主要介紹了Springboot集成RabbitMQ死信隊(duì)列的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
詳解Android系統(tǒng)中的root權(quán)限獲得原理
這篇文章主要介紹了詳解Android系統(tǒng)中的Root權(quán)限獲得原理,安卓基于Linux,所以原理也相當(dāng)于Linux中的root用戶,需要的朋友可以參考下2015-08-08
Java語(yǔ)言中的數(shù)據(jù)類(lèi)型及其用途詳解
這篇文章主要介紹了Java語(yǔ)言中的數(shù)據(jù)類(lèi)型及其用途,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
spring?boot自帶的page分頁(yè)問(wèn)題
這篇文章主要介紹了spring?boot自帶的page分頁(yè)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
打開(kāi).properties中文顯示unicode編碼問(wèn)題以及解決
這篇文章主要介紹了打開(kāi).properties中文顯示unicode編碼問(wèn)題以及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
spring cloud整合ribbon問(wèn)題及解決方案
很多小伙伴在整合ribbon都出了相同的問(wèn)題,今天特地為大家整理了該問(wèn)題的解決方案,文中有非常詳細(xì)的圖文解說(shuō),對(duì)出現(xiàn)同樣問(wèn)題的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05
劍指Offer之Java算法習(xí)題精講數(shù)組與列表的查找及字符串轉(zhuǎn)換
跟著思路走,之后從簡(jiǎn)單題入手,反復(fù)去看,做過(guò)之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化2022-03-03

