Skip to content

Commit b3dff80

Browse files
committed
add example for ddd
1 parent 5aba5ac commit b3dff80

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1637
-0
lines changed

domain-driven-design/c/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
## C语言`DDD`目录结构
2+
```bash
3+
c/
4+
├── main.c // UI 层:应用程序的入口,处理用户交互
5+
├── domain/ // 领域层:包含核心业务模型和逻辑
6+
│ ├── order.h // 订单领域模型的头文件,定义订单属性和操作
7+
│ └── order.c // 订单领域模型的实现,包含订单创建、取消等功能
8+
├── repository/ // 仓储层:管理数据存储和检索
9+
│ ├── order_repository.h // 订单仓储的头文件,声明订单持久化的函数
10+
│ └── order_repository.c // 订单仓储的实现,处理订单的保存和检索
11+
└── service/ // 服务层:提供高层业务逻辑
12+
├── order_service.h // 订单服务的头文件,声明订单操作的服务函数
13+
└── order_service.c // 订单服务的实现,协调领域和仓储操作
14+
```
15+
16+
17+
## 解释
18+
19+
- **`main.c`**: 该文件作为用户界面层,负责与用户交互,捕获输入并显示输出。它调用服务层来根据用户输入执行操作。
20+
21+
- **`domain/`**: 该目录包含领域层,是业务逻辑的核心。包括:
22+
- `order.h`: 定义 `Order` 结构体及其相关操作,如创建和取消订单。
23+
- `order.c`: 实现 `order.h` 中声明的函数,处理订单管理的核心逻辑。
24+
25+
- **`repository/`**: 该目录代表仓储层,抽象数据存储机制。包括:
26+
- `order_repository.h`: 声明用于保存和检索订单的函数。
27+
- `order_repository.c`: 实现仓储函数,管理订单数据的存储和检索。
28+
29+
- **`service/`**: 该目录包含服务层,提供高层次的业务服务。包括:
30+
- `order_service.h`: 声明协调领域和仓储层操作的服务函数。
31+
- `order_service.c`: 实现服务函数,组织业务逻辑和数据访问。
32+
33+
## 运行代码
34+
```shell
35+
$ c % make clean
36+
rm -f main.o domain/order.o repository/order_repository.o service/order_service.o order_system.o
37+
$ c % make
38+
gcc -Wall -Wextra -I./domain -I./repository -I./service -c -o main.o main.c
39+
gcc -Wall -Wextra -I./domain -I./repository -I./service -c -o domain/order.o domain/order.c
40+
gcc -Wall -Wextra -I./domain -I./repository -I./service -c -o repository/order_repository.o repository/order_repository.c
41+
gcc -Wall -Wextra -I./domain -I./repository -I./service -c -o service/order_service.o service/order_service.c
42+
gcc main.o domain/order.o repository/order_repository.o service/order_service.o -o order_system.o
43+
$ c % ./order_system.o
44+
# 展示结果
45+
```

domain-driven-design/c/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Apple clang version 16.0.0 (clang-1600.0.26.6)
6565
Target: arm64-apple-darwin24.3.0
6666
Thread model: posix
6767
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
68+
jarry@MacBook-Pro c % make clean
6869
jarry@MacBook-Pro c % make
6970
gcc main.o domain/order.o repository/order_repository.o service/order_service.o -o order_system.o
7071
jarry@MacBook-Pro c % ./order_system.o

domain-driven-design/go-web/README.md

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
## Go语言`DDD`目录结构
2+
```bash
3+
go-order-system/
4+
│── cmd/
5+
│ └── main.go # 应用入口
6+
│── internal/
7+
│ ├── domain/ # 领域层(核心业务逻辑和接口定义)
8+
│ │ ├── order/ # 订单聚合
9+
│ │ │ ├── order.go # 订单实体(聚合根),包含核心业务逻辑
10+
│ │ │ └── order_repository.go # 订单仓储接口,定义对订单数据的操作
11+
│ ├── application/ # 应用层(协调领域逻辑,处理业务用例)
12+
│ │ ├── order_service.go # 订单应用服务,调用领域层业务逻辑
13+
│ ├── infrastructure/ # 基础设施层(实现领域层定义的接口)
14+
│ │ ├── repository/ # 仓储实现
15+
│ │ │ ├── repository.go # 通用仓库接口(通用 CRUD 操作)
16+
│ │ │ └── order_repository_impl.go # 订单仓储实现,具体的订单数据存储
17+
│ └── interfaces/ # 接口层(处理外部请求,如HTTP接口)
18+
│ │ ├── handlers/ # HTTP 处理器
19+
│ │ └── order_handler.go # 订单相关的HTTP处理器
20+
│ └── middleware/ # 中间件(例如:鉴权、拦截、认证等)
21+
│── pkg/ # 可复用的公共库
22+
│ └── utils/ # 工具类(例如:日志、日期处理等)
23+
```
24+
25+
## 运行
26+
```bash
27+
$ go run cmd/main.go
28+
# 展示结果 Starting server on :8080 successfully.
29+
# 通过 http://localhost:8080 访问系统
30+
```
31+
32+
## Go 语言 DDD(领域驱动设计)特点
33+
34+
### 1. 关注领域模型
35+
DDD 强调领域模型的构建,使用 **聚合(Aggregate)****实体(Entity)****值对象(Value Object)** 组织业务逻辑。
36+
37+
在 Go 语言中,通常使用 `struct` 定义实体和值对象:
38+
39+
```go
40+
// 实体(Entity)
41+
type User struct {
42+
ID int
43+
Name string
44+
}
45+
```
46+
47+
### 2. 分层架构
48+
DDD 通常采用 **分层架构**,Go 语言项目可以遵循如下结构:
49+
50+
- **领域层(Domain Layer)**:核心业务逻辑,如 `domain` 目录下的实体和聚合。
51+
- **应用层(Application Layer)**:用例(Use Cases)和业务流程编排。
52+
- **基础设施层(Infrastructure Layer)**:数据库、缓存、外部 API 适配等。
53+
- **接口层(Interface Layer)**:提供 HTTP、gRPC 或 CLI 接口。
54+
55+
### 3. 依赖倒置(Dependency Inversion)
56+
领域层不应直接依赖基础设施,而是通过 **接口(Interface)** 进行依赖倒置。例如:
57+
58+
```go
59+
// 领域层:定义接口
60+
type UserRepository interface {
61+
GetByID(id int) (*User, error)
62+
}
63+
```
64+
65+
```go
66+
// 基础设施层:数据库实现
67+
type userRepositoryImpl struct {
68+
db *sql.DB
69+
}
70+
71+
func (r *userRepositoryImpl) GetByID(id int) (*User, error) {
72+
// 数据库查询逻辑
73+
}
74+
```
75+
76+
### 4. 聚合(Aggregate)管理
77+
78+
聚合根(Aggregate Root)管理整个聚合的生命周期:
79+
80+
```go
81+
type Order struct {
82+
ID int
83+
Items []OrderItem
84+
Status string
85+
}
86+
87+
func (o *Order) AddItem(item OrderItem) {
88+
o.Items = append(o.Items, item)
89+
}
90+
```
91+
92+
### 5. 应用服务(Application Service)
93+
应用服务封装领域逻辑,避免外部直接操作领域对象:
94+
95+
```go
96+
type OrderService struct {
97+
repo OrderRepository
98+
}
99+
100+
func (s *OrderService) CreateOrder(userID int, items []OrderItem) (*Order, error) {
101+
order := Order{UserID: userID, Items: items, Status: "Pending"}
102+
return s.repo.Save(order)
103+
}
104+
```
105+
106+
### 6. 事件驱动(Event-Driven)
107+
使用 **领域事件(Domain Events)** 进行解耦,在 Go 语言中可通过 **Channel****Pub/Sub** 实现:
108+
109+
```go
110+
type OrderCreatedEvent struct {
111+
OrderID int
112+
}
113+
114+
def publishEvent(event OrderCreatedEvent) {
115+
go func() {
116+
eventChannel <- event
117+
}()
118+
}
119+
```
120+
121+
### 7. 结合 CQRS(命令查询职责分离)
122+
DDD 可结合 CQRS(Command Query Responsibility Segregation),在 Go 语言中可用 **命令(Command)** 处理变更操作,用 **查询(Query)** 处理数据读取:
123+
124+
```go
125+
type CreateOrderCommand struct {
126+
UserID int
127+
Items []OrderItem
128+
}
129+
130+
func (h *OrderHandler) Handle(cmd CreateOrderCommand) (*Order, error) {
131+
return h.service.CreateOrder(cmd.UserID, cmd.Items)
132+
}
133+
```
134+
135+
### 总结
136+
137+
Go 语言的 DDD 实践强调:
138+
139+
1. **使用 struct 作为领域模型**(Entity、Value Object、Aggregate)
140+
2. **依赖倒置**,通过接口定义领域层,不直接依赖基础设施
141+
3. **使用应用服务(Service)封装业务逻辑**,避免外部直接操作领域对象
142+
4. **事件驱动**,通过 Channel 或 Pub/Sub 进行解耦
143+
5. **结合 CQRS**,实现命令和查询分离,提高可扩展性
144+
145+
通过 DDD 设计模式,可以使得项目业务逻辑更加清晰、模块化,便于扩展和维护。
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// 入口页面
2+
package main
3+
4+
import (
5+
"go-order-system/internal/application"
6+
"go-order-system/internal/infrastructure/repository"
7+
"go-order-system/internal/interfaces/handlers"
8+
"go-order-system/internal/middleware"
9+
"log"
10+
"net/http"
11+
)
12+
13+
// 默认欢迎页面
14+
func defaultPage(w http.ResponseWriter, r *http.Request) {
15+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
16+
w.WriteHeader(http.StatusOK)
17+
18+
htmlResponse := `
19+
<h1>Welcome to DDD example.</h1>
20+
<pre>
21+
测试
22+
<code>
23+
创建:curl -X POST "http://localhost:8080/orders/create" -H "Content-Type: application/json" -d '{"customer_name": "齐天大圣", "total_amount": 99.99}'
24+
查询:curl -X GET "http://localhost:8080/orders/get?id=订单号"
25+
更新:curl -X PUT "http://localhost:8080/orders/update?id=订单号" -H "Content-Type: application/json" -d '{"customer_name": "孙悟空", "total_amount": 11.22}'
26+
删除:curl -X DELETE "http://localhost:8080/orders/delete?id=订单号"
27+
查询:curl -X GET "http://localhost:8080/orders/get?id=订单号"
28+
</code>
29+
</pre>
30+
`
31+
w.Write([]byte(htmlResponse))
32+
}
33+
34+
func initRouter(orderHandler *handlers.OrderHandler) {
35+
// 配置路由并将中间件应用到每个处理器
36+
http.HandleFunc("/", middleware.LoggingMiddleware(defaultPage)) // 欢迎页面
37+
http.HandleFunc("/orders/create", middleware.LoggingMiddleware(orderHandler.CreateOrder)) // 创建订单
38+
http.HandleFunc("/orders/get", middleware.LoggingMiddleware(orderHandler.GetOrder)) // 查询订单
39+
http.HandleFunc("/orders/update", middleware.LoggingMiddleware(orderHandler.UpdateOrder)) // 更新订单
40+
http.HandleFunc("/orders/delete", middleware.LoggingMiddleware(orderHandler.DeleteOrder)) // 删除订单
41+
}
42+
43+
func main() {
44+
// 创建订单仓储实现
45+
orderRepo := repository.NewOrderRepositoryImpl()
46+
47+
// 创建订单应用服务
48+
orderService := application.NewOrderService(orderRepo)
49+
50+
// 创建 HTTP 处理器
51+
orderHandler := handlers.NewOrderHandler(orderService)
52+
53+
initRouter(orderHandler)
54+
55+
// 打印日志确认服务器启动
56+
log.Println("Starting server on :8080 successfully.")
57+
58+
// 启动 HTTP 服务器
59+
if err := http.ListenAndServe(":8080", nil); err != nil {
60+
log.Fatalf("Server failed: %v", err)
61+
}
62+
}
63+
64+
/*
65+
// 在控制台运行项目
66+
jarry@MacBook-Pro go-web % go run cmd/main.go
67+
68+
// 执行curl测试,可以得到结果,控制台输出如下
69+
2023/04/21 15:43:45 Starting server on :8080 successfully.
70+
2023/04/21 15:43:50 REQUEST: POST /orders/create took 147.375µs
71+
2023/04/21 15:44:00 REQUEST: GET /orders/get took 152.833µs
72+
2023/04/21 15:44:20 REQUEST: PUT /orders/update took 140µs
73+
2023/04/21 15:44:29 REQUEST: GET /orders/get took 44µs
74+
2023/04/21 15:44:41 REQUEST: DELETE /orders/delete took 116.167µs
75+
2023/04/21 15:44:44 REQUEST: GET /orders/get took 13.166µs
76+
*/

domain-driven-design/go-web/go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module go-order-system
2+
3+
go 1.19
4+
5+
require github.com/gorilla/mux v1.8.1

domain-driven-design/go-web/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
2+
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// 应用层(协调领域逻辑,处理业务用例):订单应用服务
2+
package application
3+
4+
import (
5+
"fmt"
6+
"go-order-system/internal/domain/order"
7+
)
8+
9+
// OrderService 订单应用服务,协调领域逻辑和业务用例
10+
type OrderService struct {
11+
OrderRepository order.OrderRepository // 订单仓储接口
12+
}
13+
14+
// 创建OrderService实例对象
15+
func NewOrderService(orderRepo order.OrderRepository) *OrderService {
16+
return &OrderService{orderRepo}
17+
}
18+
19+
// CreateOrder 创建订单并保存到仓储中
20+
func (s *OrderService) CreateOrder(id int, customerName string, amount float64) (*order.Order, error) {
21+
// 创建订单
22+
newOrder := order.NewOrder(id, customerName, amount)
23+
if newOrder == nil {
24+
return nil, fmt.Errorf("订单创建失败")
25+
}
26+
27+
// 保存订单
28+
err := s.OrderRepository.Save(newOrder)
29+
if err != nil {
30+
return nil, fmt.Errorf("订单保存失败: %v", err)
31+
}
32+
33+
return newOrder, nil
34+
}
35+
36+
// CancelOrder 取消订单
37+
func (s *OrderService) CancelOrder(id int) error {
38+
order, err := s.OrderRepository.FindByID(id) // 获取订单
39+
if err != nil {
40+
return fmt.Errorf("订单取消失败:%v", err)
41+
}
42+
43+
order.Cancel() // 执行领域逻辑:取消订单
44+
err = s.OrderRepository.Save(order) // 保存更新后的订单
45+
if err != nil {
46+
return fmt.Errorf("订单取消失败:%v", err)
47+
}
48+
return nil
49+
}
50+
51+
// GetOrder 查询订单
52+
func (s *OrderService) GetOrder(id int) (*order.Order, error) {
53+
return s.OrderRepository.FindByID(id)
54+
}
55+
56+
// UpdateOrder 更新订单的客户信息和金额
57+
func (s *OrderService) UpdateOrder(id int, customerName string, amount float64) (*order.Order, error) {
58+
// 获取订单
59+
order, err := s.OrderRepository.FindByID(id)
60+
if err != nil {
61+
return nil, fmt.Errorf("订单未找到: %v", err)
62+
}
63+
64+
// 更新订单的客户信息和金额
65+
order.UpdateCustomerInfo(customerName)
66+
order.UpdateAmount(amount)
67+
68+
// 保存更新后的订单
69+
err = s.OrderRepository.Save(order)
70+
if err != nil {
71+
return nil, fmt.Errorf("更新订单失败: %v", err)
72+
}
73+
74+
return order, nil
75+
}
76+
77+
// DeleteOrder 删除订单
78+
func (s *OrderService) DeleteOrder(id int) error {
79+
// 获取订单
80+
order, err := s.OrderRepository.FindByID(id)
81+
if err != nil {
82+
return fmt.Errorf("订单未找到: %v", err)
83+
}
84+
// 从仓储中删除订单
85+
err = s.OrderRepository.Delete(order.ID)
86+
if err != nil {
87+
return fmt.Errorf("删除订单失败: %v", err)
88+
}
89+
90+
return nil
91+
}

0 commit comments

Comments
 (0)