经典三层(使用最广)
┌──────────────────────────┐
│ 表示层 (UI) │ ← Controller / View
├──────────────────────────┤
│ 业务逻辑层 │ ← Service / UseCase
├──────────────────────────┤
│ 数据访问层 │ ← Repository / DAO
└──────────────────────────┘
依赖方向:表示层 → 业务层 → 数据层
业务层不依赖具体 UI 或数据库实现
// 三层示例 — C++
class UserRepository { // 数据层
public:
virtual User findById(int id) = 0;
};
class SqlUserRepo : public UserRepository {
User findById(int id) override { /* SELECT */ }
};
class UserService { // 业务层(依赖接口,不依赖实现)
UserRepository &repo;
public:
UserService(UserRepository &r) : repo(r) {}
User getProfile(int id) { return repo.findById(id); }
};
class UserController { // 表示层
UserService &svc;
public:
Json handleRequest(int id) {
auto user = svc.getProfile(id);
return user.toJson();
}
};
三层选择考量
| 考量 | 三层 |
|---|
| 简单项目(<10 个接口) | ✅ 刚好 |
| 业务逻辑复杂、多变 | ⚠️ Service 容易膨胀 |
| 多端 UI(Web/桌面/移动) | ✅ 复用业务层 |
| 需要替换数据库 | ✅ Repository 接口隔离 |
DDD(领域驱动设计)
┌──────────────────────────────┐
│ 接口层 (API/UI) │
├──────────────────────────────┤
│ 应用层 (UseCase) │ ← 编排领域对象
├──────────────────────────────┤
│ 领域层 (Entity/ValueObj) │ ← 核心业务规则
│ ┌──────────┬──────────┐ │
│ │ 聚合根 │ 领域服务 │ │
│ │ 值对象 │ 领域事件 │ │
│ └──────────┴──────────┘ │
├──────────────────────────────┤
│ 基础设施层 (DB/MQ/Cache) │
└──────────────────────────────┘
依赖方向:全部指向领域层(领域层不依赖任何外部)
// DDD 示例 — 订单领域
class Money { // 值对象(无 ID,不可变)
double amount;
string currency;
public:
Money add(const Money &other) const {
if (currency != other.currency) throw ...;
return {amount + other.amount, currency};
}
};
class Order { // 实体 / 聚合根
int id; // 实体的标识
Money total;
OrderStatus status;
public:
void addItem(const Item &item) {
total = total.add(item.price); // 业务规则在领域内
}
void submit() {
if (status != OrderStatus::Draft) throw ...;
status = OrderStatus::Submitted;
}
};
DDD 选择考量
| 考量 | DDD |
|---|
| 业务规则复杂多变 | ✅ 业务规则归位到领域对象 |
| 团队懂业务语言 | ✅ 统一语言(Ubiquitous Language) |
| 简单 CRUD 项目 | ❌ 过度设计 |
| 团队大、需要分模块 | ✅ 限界上下文(Bounded Context) |
六边形架构(端口-适配器)
┌──────────────────┐
Web ──→│ │──→ DB
│ 业务核心 │
REST ──→│ (无外部依赖) │──→ MQ
│ │
CLI ──→│ │──→ Cache
└──────────────────┘
← 主端口 (输入) 次端口 (输出) →
// 端口 = 接口
class OrderRepository { // 次端口(输出端口)
public:
virtual void save(const Order &order) = 0;
};
class OrderUseCase { // 业务核心
OrderRepository &repo;
public:
void submitOrder(Order &order) {
order.submit();
repo.save(order);
}
};
// 适配器 = 接口的具体实现
class PostgresOrderRepo : public OrderRepository { /* ... */ };
class MongoOrderRepo : public OrderRepository { /* ... */ };
六边形选择考量
| 考量 | 六边形 |
|---|
| 需要替换基础设施 | ✅ 换数据库只需新适配器 |
| 多输入渠道 | ✅ Web / CLI / 消息队列统一 |
| 测试驱动 | ✅ 所有依赖可 mock |
| 小项目 | ❌ 接口数量爆炸 |
CQRS(读写分离)
┌─────────────┐
写请求 → Command → 写 Model → DB (主)
└─────────────┘
┌─────────────┐
读请求 → Query → 读 Model → DB (从) / ES
└─────────────┘
// 命令侧 — 只管写
class CreateOrderCommand {
int userId;
vector<Item> items;
};
class CreateOrderHandler {
void handle(const CreateOrderCommand &cmd) {
Order order = Order::create(cmd.userId, cmd.items);
orderRepo.save(order);
eventBus.publish(OrderCreatedEvent{order.id()});
}
};
// 查询侧 — 只管读(可走缓存/只读副本/ES)
class OrderQueryService {
OrderDTO findById(int id) {
// 可能直接查 ES / Redis / 只读从库
return readDb.query("SELECT ...").mapTo<OrderDTO>();
}
};
CQRS 选择考量
| 考量 | CQRS |
|---|
| 读 >> 写(报表/仪表盘) | ✅ 读模型专门优化 |
| 读写模型差异大 | ✅ 互不干扰 |
| 简单 CRUD | ❌ 双倍模型,过度设计 |
| 团队小 | ❌ 维护成本高 |
分层决策树
业务逻辑复杂 + 领域专家参与?
├─ 是 → DDD(四层 + 限界上下文)
└─ 否 → CRUD 为主?
├─ 是 → 经典三层
└─ 否 → 需要频繁替换基础设施?
├─ 是 → 六边形架构
└─ 否 → 读写压力差异大?
├─ 是 → CQRS
└─ 否 → 三层(够了)
层间依赖规则(所有架构适用)
1. 上层依赖下层,下层不依赖上层(依赖倒置)
2. 层间通信尽量通过接口(类型擦除)
3. 同一层的组件可以互相引用
4. 禁止跨层调用(表示层绝对不能直接调 DAO)
5. 数据对象不跨层「裸奔」— DTO/Entity 转换在层边界