洋葱架构
📖 概述
洋葱架构(Onion Architecture)是由Jeffrey Palermo提出的一种软件架构模式,它强调依赖方向从外层指向内层,确保核心业务逻辑不依赖于外部基础设施。这种架构通过分层设计实现高度的可测试性和可维护性。
🎯 学习目标
- 理解洋葱架构的分层设计原则
- 掌握依赖反转和控制反转技术
- 学习领域驱动设计在洋葱架构中的应用
- 实现可测试的分层企业应用
🧅 洋葱架构层次设计
1. 架构层次实现
javascript
// 洋葱架构核心框架
class OnionArchitecture {
constructor() {
this.domainCore = new DomainCore() // 最内层:领域核心
this.domainServices = new DomainServices() // 第二层:领域服务
this.applicationCore = new ApplicationCore() // 第三层:应用核心
this.infrastructure = new Infrastructure() // 最外层:基础设施
}
// 第一层:领域核心(Domain Core)
class DomainCore {
constructor() {
this.entities = new Map()
this.valueObjects = new Map()
this.domainEvents = new Map()
this.specifications = new Map()
}
// 聚合根实体
defineAggregateRoot(aggregateConfig) {
class AggregateRoot {
constructor(id, data = {}) {
this.id = id
this.version = 0
this.createdAt = new Date()
this.updatedAt = new Date()
this.domainEvents = []
this.isDeleted = false
Object.assign(this, data)
// 应用创建时的业务规则
this.applyCreationRules()
}
// 业务规则验证
validate() {
const errors = []
const rules = aggregateConfig.businessRules || []
rules.forEach(rule => {
if (!rule.validate(this)) {
errors.push({
rule: rule.name,
message: rule.message,
field: rule.field
})
}
})
return {
isValid: errors.length === 0,
errors
}
}
// 应用业务规则
applyBusinessRule(ruleName, data) {
const rule = aggregateConfig.businessRules?.find(r => r.name === ruleName)
if (!rule) {
throw new Error(`业务规则不存在: ${ruleName}`)
}
// 前置条件检查
if (rule.precondition && !rule.precondition(this, data)) {
throw new Error(`业务规则前置条件不满足: ${ruleName}`)
}
// 应用规则
const result = rule.apply(this, data)
// 更新版本和时间戳
this.version++
this.updatedAt = new Date()
// 记录领域事件
if (rule.event) {
this.addDomainEvent(rule.event, result)
}
return result
}
// 添加领域事件
addDomainEvent(eventType, data) {
const event = {
id: this.generateEventId(),
type: eventType,
aggregateId: this.id,
aggregateType: aggregateConfig.name,
version: this.version,
data,
occurredAt: new Date()
}
this.domainEvents.push(event)
console.log(`领域事件添加: ${eventType}`)
return event
}
// 获取未提交的领域事件
getUncommittedEvents() {
return [...this.domainEvents]
}
// 标记事件为已提交
markEventsAsCommitted() {
this.domainEvents = []
}
// 软删除
markAsDeleted() {
if (this.isDeleted) {
throw new Error('聚合根已被删除')
}
this.isDeleted = true
this.updatedAt = new Date()
this.addDomainEvent(`${aggregateConfig.name}Deleted`, {
deletedAt: this.updatedAt
})
}
applyCreationRules() {
// 应用创建时的验证规则
const validation = this.validate()
if (!validation.isValid) {
throw new Error(`聚合根创建失败: ${validation.errors.map(e => e.message).join(', ')}`)
}
// 触发创建事件
this.addDomainEvent(`${aggregateConfig.name}Created`, {
id: this.id,
createdAt: this.createdAt
})
}
generateEventId() {
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
}
}
this.entities.set(aggregateConfig.name, AggregateRoot)
console.log(`聚合根定义完成: ${aggregateConfig.name}`)
return AggregateRoot
}
// 值对象定义
defineValueObject(valueObjectConfig) {
class ValueObject {
constructor(data) {
// 验证输入数据
const validation = this.validateInput(data)
if (!validation.isValid) {
throw new Error(`值对象创建失败: ${validation.errors.join(', ')}`)
}
Object.assign(this, data)
Object.freeze(this) // 值对象不可变
}
// 值相等性比较
equals(other) {
if (!other || other.constructor !== this.constructor) {
return false
}
return this.getIdentityFields().every(field => {
return this[field] === other[field]
})
}
// 获取标识字段
getIdentityFields() {
return valueObjectConfig.identityFields || Object.keys(this)
}
// 输入验证
validateInput(data) {
const errors = []
const rules = valueObjectConfig.validationRules || []
rules.forEach(rule => {
if (!rule.validate(data)) {
errors.push(rule.message)
}
})
return {
isValid: errors.length === 0,
errors
}
}
// 创建新的值对象(不可变性)
withChanges(changes) {
const newData = { ...this, ...changes }
return new this.constructor(newData)
}
toString() {
return JSON.stringify(this)
}
}
this.valueObjects.set(valueObjectConfig.name, ValueObject)
console.log(`值对象定义完成: ${valueObjectConfig.name}`)
return ValueObject
}
// 规约模式实现
defineSpecification(specConfig) {
class Specification {
constructor() {
this.name = specConfig.name
this.description = specConfig.description
}
// 是否满足规约
isSatisfiedBy(candidate) {
return specConfig.criteria(candidate)
}
// 与操作
and(other) {
return new CompositeSpecification(
this.name + '_AND_' + other.name,
(candidate) => this.isSatisfiedBy(candidate) && other.isSatisfiedBy(candidate)
)
}
// 或操作
or(other) {
return new CompositeSpecification(
this.name + '_OR_' + other.name,
(candidate) => this.isSatisfiedBy(candidate) || other.isSatisfiedBy(candidate)
)
}
// 非操作
not() {
return new CompositeSpecification(
'NOT_' + this.name,
(candidate) => !this.isSatisfiedBy(candidate)
)
}
}
this.specifications.set(specConfig.name, Specification)
console.log(`规约定义完成: ${specConfig.name}`)
return Specification
}
}
// 第二层:领域服务(Domain Services)
class DomainServices {
constructor() {
this.services = new Map()
this.factories = new Map()
}
// 领域服务定义
defineDomainService(serviceConfig) {
class DomainService {
constructor() {
this.name = serviceConfig.name
this.description = serviceConfig.description
}
// 执行领域逻辑
async execute(operation, context, data) {
console.log(`执行领域服务: ${this.name}.${operation}`)
try {
// 前置条件检查
await this.checkPreconditions(operation, context, data)
// 执行业务逻辑
const operationHandler = serviceConfig.operations[operation]
if (!operationHandler) {
throw new Error(`操作不存在: ${operation}`)
}
const result = await operationHandler(context, data)
// 后置条件检查
await this.checkPostconditions(operation, context, data, result)
return result
} catch (error) {
console.error(`领域服务执行失败: ${this.name}.${operation}`, error)
throw error
}
}
async checkPreconditions(operation, context, data) {
const precondition = serviceConfig.preconditions?.[operation]
if (precondition && !await precondition(context, data)) {
throw new Error(`前置条件不满足: ${operation}`)
}
}
async checkPostconditions(operation, context, data, result) {
const postcondition = serviceConfig.postconditions?.[operation]
if (postcondition && !await postcondition(context, data, result)) {
throw new Error(`后置条件不满足: ${operation}`)
}
}
}
this.services.set(serviceConfig.name, DomainService)
console.log(`领域服务定义完成: ${serviceConfig.name}`)
return DomainService
}
// 聚合工厂
defineAggregateFactory(factoryConfig) {
class AggregateFactory {
constructor() {
this.name = factoryConfig.name
this.aggregateType = factoryConfig.aggregateType
}
// 创建聚合根
async create(data, context = {}) {
console.log(`创建聚合: ${this.aggregateType}`)
try {
// 数据预处理
const processedData = await this.preprocessData(data, context)
// 生成ID
const id = await this.generateId(processedData, context)
// 创建聚合根
const AggregateClass = factoryConfig.aggregateClass
const aggregate = new AggregateClass(id, processedData)
// 应用创建后的业务规则
await this.applyPostCreationRules(aggregate, context)
console.log(`聚合创建成功: ${this.aggregateType}[${id}]`)
return aggregate
} catch (error) {
console.error(`聚合创建失败: ${this.aggregateType}`, error)
throw error
}
}
// 重建聚合(从持久化状态)
async reconstitute(id, data, events = []) {
console.log(`重建聚合: ${this.aggregateType}[${id}]`)
const AggregateClass = factoryConfig.aggregateClass
const aggregate = new AggregateClass(id, data)
// 重播事件
for (const event of events) {
await this.applyEvent(aggregate, event)
}
// 清除未提交的事件(因为是重建)
aggregate.markEventsAsCommitted()
return aggregate
}
async preprocessData(data, context) {
if (factoryConfig.dataPreprocessor) {
return await factoryConfig.dataPreprocessor(data, context)
}
return data
}
async generateId(data, context) {
if (factoryConfig.idGenerator) {
return await factoryConfig.idGenerator(data, context)
}
return `${this.aggregateType}-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`
}
async applyPostCreationRules(aggregate, context) {
const rules = factoryConfig.postCreationRules || []
for (const rule of rules) {
await rule(aggregate, context)
}
}
async applyEvent(aggregate, event) {
const eventHandler = factoryConfig.eventHandlers?.[event.type]
if (eventHandler) {
await eventHandler(aggregate, event)
}
}
}
this.factories.set(factoryConfig.name, AggregateFactory)
console.log(`聚合工厂定义完成: ${factoryConfig.name}`)
return AggregateFactory
}
}
// 第三层:应用核心(Application Core)
class ApplicationCore {
constructor() {
this.useCases = new Map()
this.applicationServices = new Map()
this.commandHandlers = new Map()
this.queryHandlers = new Map()
this.eventHandlers = new Map()
}
// 用例定义
defineUseCase(useCaseConfig) {
class UseCase {
constructor(dependencies) {
this.dependencies = dependencies
this.name = useCaseConfig.name
this.description = useCaseConfig.description
}
async execute(request, context = {}) {
console.log(`执行用例: ${this.name}`)
const executionContext = {
...context,
useCaseName: this.name,
startTime: new Date(),
requestId: this.generateRequestId()
}
try {
// 请求验证
await this.validateRequest(request, executionContext)
// 权限检查
await this.checkAuthorization(request, executionContext)
// 执行业务逻辑
const result = await this.executeBusinessLogic(request, executionContext)
// 结果验证
await this.validateResult(result, executionContext)
// 记录成功
this.logSuccess(executionContext, result)
return {
success: true,
data: result,
metadata: {
executionTime: Date.now() - executionContext.startTime.getTime(),
requestId: executionContext.requestId
}
}
} catch (error) {
this.logError(executionContext, error)
return {
success: false,
error: {
message: error.message,
type: error.constructor.name,
code: error.code || 'UNKNOWN_ERROR'
},
metadata: {
executionTime: Date.now() - executionContext.startTime.getTime(),
requestId: executionContext.requestId
}
}
}
}
async validateRequest(request, context) {
const validator = useCaseConfig.requestValidator
if (validator) {
const validation = await validator(request, context)
if (!validation.isValid) {
throw new Error(`请求验证失败: ${validation.errors.join(', ')}`)
}
}
}
async checkAuthorization(request, context) {
const authChecker = useCaseConfig.authorizationChecker
if (authChecker) {
const isAuthorized = await authChecker(request, context)
if (!isAuthorized) {
throw new Error('权限不足')
}
}
}
async executeBusinessLogic(request, context) {
return await useCaseConfig.executor(request, context, this.dependencies)
}
async validateResult(result, context) {
const validator = useCaseConfig.resultValidator
if (validator) {
const validation = await validator(result, context)
if (!validation.isValid) {
throw new Error(`结果验证失败: ${validation.errors.join(', ')}`)
}
}
}
logSuccess(context, result) {
console.log(`用例执行成功: ${this.name}`, {
requestId: context.requestId,
executionTime: Date.now() - context.startTime.getTime()
})
}
logError(context, error) {
console.error(`用例执行失败: ${this.name}`, {
requestId: context.requestId,
error: error.message,
executionTime: Date.now() - context.startTime.getTime()
})
}
generateRequestId() {
return `REQ-${Date.now()}-${Math.random().toString(36).substr(2, 8)}`
}
}
this.useCases.set(useCaseConfig.name, UseCase)
console.log(`用例定义完成: ${useCaseConfig.name}`)
return UseCase
}
// CQRS 命令处理器
defineCommandHandler(handlerConfig) {
class CommandHandler {
constructor(dependencies) {
this.dependencies = dependencies
this.commandType = handlerConfig.commandType
}
async handle(command, context = {}) {
console.log(`处理命令: ${this.commandType}`)
try {
// 命令验证
await this.validateCommand(command, context)
// 获取聚合根
const aggregate = await this.loadAggregate(command, context)
// 执行命令
const result = await this.executeCommand(aggregate, command, context)
// 保存聚合根
await this.saveAggregate(aggregate, context)
// 发布领域事件
await this.publishDomainEvents(aggregate, context)
return result
} catch (error) {
console.error(`命令处理失败: ${this.commandType}`, error)
throw error
}
}
async validateCommand(command, context) {
const validator = handlerConfig.validator
if (validator) {
const validation = await validator(command, context)
if (!validation.isValid) {
throw new Error(`命令验证失败: ${validation.errors.join(', ')}`)
}
}
}
async loadAggregate(command, context) {
const loader = handlerConfig.aggregateLoader
if (!loader) {
throw new Error('聚合加载器未定义')
}
return await loader(command, context, this.dependencies)
}
async executeCommand(aggregate, command, context) {
const executor = handlerConfig.executor
if (!executor) {
throw new Error('命令执行器未定义')
}
return await executor(aggregate, command, context, this.dependencies)
}
async saveAggregate(aggregate, context) {
const saver = handlerConfig.aggregateSaver
if (!saver) {
throw new Error('聚合保存器未定义')
}
return await saver(aggregate, context, this.dependencies)
}
async publishDomainEvents(aggregate, context) {
const events = aggregate.getUncommittedEvents()
for (const event of events) {
await this.dependencies.eventBus.publish(event, context)
}
aggregate.markEventsAsCommitted()
}
}
this.commandHandlers.set(handlerConfig.commandType, CommandHandler)
console.log(`命令处理器定义完成: ${handlerConfig.commandType}`)
return CommandHandler
}
// CQRS 查询处理器
defineQueryHandler(handlerConfig) {
class QueryHandler {
constructor(dependencies) {
this.dependencies = dependencies
this.queryType = handlerConfig.queryType
}
async handle(query, context = {}) {
console.log(`处理查询: ${this.queryType}`)
try {
// 查询验证
await this.validateQuery(query, context)
// 权限检查
await this.checkQueryPermissions(query, context)
// 执行查询
const result = await this.executeQuery(query, context)
// 结果后处理
const processedResult = await this.postProcessResult(result, query, context)
return processedResult
} catch (error) {
console.error(`查询处理失败: ${this.queryType}`, error)
throw error
}
}
async validateQuery(query, context) {
const validator = handlerConfig.validator
if (validator) {
const validation = await validator(query, context)
if (!validation.isValid) {
throw new Error(`查询验证失败: ${validation.errors.join(', ')}`)
}
}
}
async checkQueryPermissions(query, context) {
const permissionChecker = handlerConfig.permissionChecker
if (permissionChecker) {
const hasPermission = await permissionChecker(query, context, this.dependencies)
if (!hasPermission) {
throw new Error('查询权限不足')
}
}
}
async executeQuery(query, context) {
const executor = handlerConfig.executor
if (!executor) {
throw new Error('查询执行器未定义')
}
return await executor(query, context, this.dependencies)
}
async postProcessResult(result, query, context) {
const postProcessor = handlerConfig.resultPostProcessor
if (postProcessor) {
return await postProcessor(result, query, context, this.dependencies)
}
return result
}
}
this.queryHandlers.set(handlerConfig.queryType, QueryHandler)
console.log(`查询处理器定义完成: ${handlerConfig.queryType}`)
return QueryHandler
}
}
// 第四层:基础设施(Infrastructure)
class Infrastructure {
constructor() {
this.repositories = new Map()
this.externalServices = new Map()
this.eventBus = new Map()
this.caching = new Map()
}
// 仓储实现
defineRepository(repositoryConfig) {
class Repository {
constructor(dataAccess, eventBus) {
this.dataAccess = dataAccess
this.eventBus = eventBus
this.aggregateType = repositoryConfig.aggregateType
}
async save(aggregate) {
console.log(`保存聚合: ${this.aggregateType}[${aggregate.id}]`)
try {
// 开始事务
const transaction = await this.dataAccess.beginTransaction()
try {
// 保存聚合数据
await this.persistAggregate(aggregate, transaction)
// 保存领域事件
const events = aggregate.getUncommittedEvents()
await this.persistEvents(events, transaction)
// 提交事务
await transaction.commit()
// 发布事件
await this.publishEvents(events)
// 标记事件为已提交
aggregate.markEventsAsCommitted()
console.log(`聚合保存成功: ${this.aggregateType}[${aggregate.id}]`)
} catch (error) {
await transaction.rollback()
throw error
}
} catch (error) {
console.error(`聚合保存失败: ${this.aggregateType}[${aggregate.id}]`, error)
throw error
}
}
async findById(id) {
console.log(`查找聚合: ${this.aggregateType}[${id}]`)
try {
const data = await this.dataAccess.findById(this.aggregateType, id)
if (!data) {
return null
}
// 加载事件历史
const events = await this.loadEvents(id)
// 重建聚合
const aggregate = await this.reconstituteAggregate(id, data, events)
return aggregate
} catch (error) {
console.error(`聚合查找失败: ${this.aggregateType}[${id}]`, error)
throw error
}
}
async findBySpecification(specification, options = {}) {
console.log(`按规约查找聚合: ${this.aggregateType}`)
try {
const criteria = this.translateSpecification(specification)
const data = await this.dataAccess.findByCriteria(this.aggregateType, criteria, options)
const aggregates = []
for (const item of data.items) {
const events = await this.loadEvents(item.id)
const aggregate = await this.reconstituteAggregate(item.id, item, events)
aggregates.push(aggregate)
}
return {
items: aggregates,
totalCount: data.totalCount,
hasMore: data.hasMore
}
} catch (error) {
console.error(`规约查找失败: ${this.aggregateType}`, error)
throw error
}
}
async persistAggregate(aggregate, transaction) {
const persistor = repositoryConfig.aggregatePersistor
if (!persistor) {
throw new Error('聚合持久化器未定义')
}
await persistor(aggregate, transaction, this.dataAccess)
}
async persistEvents(events, transaction) {
for (const event of events) {
await this.dataAccess.saveEvent(event, transaction)
}
}
async publishEvents(events) {
for (const event of events) {
await this.eventBus.publish(event)
}
}
async loadEvents(aggregateId) {
return await this.dataAccess.loadEvents(this.aggregateType, aggregateId)
}
async reconstituteAggregate(id, data, events) {
const factory = repositoryConfig.aggregateFactory
if (!factory) {
throw new Error('聚合工厂未定义')
}
return await factory.reconstitute(id, data, events)
}
translateSpecification(specification) {
const translator = repositoryConfig.specificationTranslator
if (!translator) {
throw new Error('规约转换器未定义')
}
return translator(specification)
}
}
this.repositories.set(repositoryConfig.aggregateType, Repository)
console.log(`仓储定义完成: ${repositoryConfig.aggregateType}`)
return Repository
}
}
}
2. 实际应用示例
javascript
// 电商订单管理系统洋葱架构实现
class ECommerceOnionArchitecture {
constructor() {
this.architecture = new OnionArchitecture()
this.setupDomain()
this.setupServices()
this.setupApplication()
this.setupInfrastructure()
}
setupDomain() {
// 订单聚合根
const OrderAggregate = this.architecture.domainCore.defineAggregateRoot({
name: 'Order',
businessRules: [
{
name: 'minimumOrderAmount',
message: '订单金额必须大于0',
validate: (order) => order.totalAmount > 0,
field: 'totalAmount'
},
{
name: 'validOrderStatus',
message: '订单状态无效',
validate: (order) => ['pending', 'confirmed', 'shipped', 'delivered', 'cancelled'].includes(order.status),
field: 'status'
},
{
name: 'confirmOrder',
message: '只有待确认订单可以确认',
precondition: (order) => order.status === 'pending',
apply: (order, data) => {
order.status = 'confirmed'
order.confirmedAt = new Date()
return { status: order.status, confirmedAt: order.confirmedAt }
},
event: 'OrderConfirmed'
},
{
name: 'cancelOrder',
message: '只有待确认或已确认订单可以取消',
precondition: (order) => ['pending', 'confirmed'].includes(order.status),
apply: (order, data) => {
order.status = 'cancelled'
order.cancelledAt = new Date()
order.cancellationReason = data.reason
return { status: order.status, cancelledAt: order.cancelledAt }
},
event: 'OrderCancelled'
}
]
})
// 订单项值对象
const OrderItem = this.architecture.domainCore.defineValueObject({
name: 'OrderItem',
identityFields: ['productId', 'variant'],
validationRules: [
{
validate: (data) => data.productId && data.productId.length > 0,
message: '产品ID不能为空'
},
{
validate: (data) => data.quantity > 0,
message: '数量必须大于0'
},
{
validate: (data) => data.unitPrice >= 0,
message: '单价不能为负数'
}
]
})
// 地址值对象
const Address = this.architecture.domainCore.defineValueObject({
name: 'Address',
identityFields: ['street', 'city', 'postalCode', 'country'],
validationRules: [
{
validate: (data) => data.street && data.street.trim().length > 0,
message: '街道地址不能为空'
},
{
validate: (data) => data.city && data.city.trim().length > 0,
message: '城市不能为空'
},
{
validate: (data) => data.postalCode && /^\d{5,6}$/.test(data.postalCode),
message: '邮编格式无效'
}
]
})
// 订单规约
const PendingOrderSpecification = this.architecture.domainCore.defineSpecification({
name: 'PendingOrderSpecification',
description: '查找待处理订单',
criteria: (order) => order.status === 'pending'
})
const HighValueOrderSpecification = this.architecture.domainCore.defineSpecification({
name: 'HighValueOrderSpecification',
description: '查找高价值订单',
criteria: (order) => order.totalAmount >= 1000
})
}
setupServices() {
// 订单领域服务
const OrderDomainService = this.architecture.domainServices.defineDomainService({
name: 'OrderDomainService',
description: '订单相关的领域逻辑',
operations: {
calculateShipping: async (context, data) => {
const { items, shippingAddress, shippingMethod } = data
let baseShippingCost = 10 // 基础运费
let weightMultiplier = 0
// 计算重量
for (const item of items) {
const product = await context.productRepository.findById(item.productId)
weightMultiplier += (product.weight || 0.5) * item.quantity
}
// 运输方式调整
const methodMultipliers = {
'standard': 1.0,
'express': 1.5,
'overnight': 2.5
}
const methodMultiplier = methodMultipliers[shippingMethod] || 1.0
return baseShippingCost + (weightMultiplier * 2) * methodMultiplier
},
validateOrderConsistency: async (context, data) => {
const { orderId } = data
const order = await context.orderRepository.findById(orderId)
if (!order) {
throw new Error('订单不存在')
}
// 验证库存
for (const item of order.items) {
const inventory = await context.inventoryRepository.findByProductId(item.productId)
if (inventory.available < item.quantity) {
throw new Error(`产品 ${item.productId} 库存不足`)
}
}
// 验证价格一致性
let calculatedTotal = 0
for (const item of order.items) {
const product = await context.productRepository.findById(item.productId)
if (product.price !== item.unitPrice) {
throw new Error(`产品 ${item.productId} 价格已变更`)
}
calculatedTotal += item.unitPrice * item.quantity
}
if (Math.abs(calculatedTotal - order.subtotal) > 0.01) {
throw new Error('订单金额计算不一致')
}
return { valid: true }
}
},
preconditions: {
calculateShipping: (context, data) => {
return data.items && data.items.length > 0 && data.shippingAddress
},
validateOrderConsistency: (context, data) => {
return data.orderId
}
}
})
// 订单工厂
const OrderFactory = this.architecture.domainServices.defineAggregateFactory({
name: 'OrderFactory',
aggregateType: 'Order',
aggregateClass: OrderAggregate,
dataPreprocessor: async (data, context) => {
// 计算订单总金额
let subtotal = 0
for (const item of data.items) {
subtotal += item.unitPrice * item.quantity
}
// 计算运费
const shippingCost = await context.orderDomainService.execute(
'calculateShipping',
context,
{
items: data.items,
shippingAddress: data.shippingAddress,
shippingMethod: data.shippingMethod || 'standard'
}
)
// 计算税费
const taxRate = 0.1 // 10% 税率
const taxAmount = subtotal * taxRate
return {
...data,
subtotal,
shippingCost,
taxAmount,
totalAmount: subtotal + shippingCost + taxAmount,
status: 'pending',
createdAt: new Date()
}
},
idGenerator: async (data, context) => {
const timestamp = Date.now()
const random = Math.random().toString(36).substr(2, 6).toUpperCase()
return `ORD-${timestamp}-${random}`
},
postCreationRules: [
async (order, context) => {
// 预留库存
for (const item of order.items) {
await context.inventoryService.reserve(item.productId, item.quantity, order.id)
}
}
]
})
}
setupApplication() {
// 创建订单用例
const CreateOrderUseCase = this.architecture.applicationCore.defineUseCase({
name: 'CreateOrderUseCase',
description: '创建新订单',
requestValidator: async (request, context) => {
const errors = []
if (!request.customerId) {
errors.push('客户ID不能为空')
}
if (!request.items || request.items.length === 0) {
errors.push('订单项不能为空')
}
if (!request.shippingAddress) {
errors.push('配送地址不能为空')
}
return {
isValid: errors.length === 0,
errors
}
},
authorizationChecker: async (request, context) => {
// 检查客户是否有效
const customer = await context.dependencies.customerRepository.findById(request.customerId)
return customer && customer.status === 'active'
},
executor: async (request, context, dependencies) => {
// 创建订单
const orderFactory = dependencies.orderFactory
const order = await orderFactory.create(request, {
...context,
...dependencies
})
// 保存订单
await dependencies.orderRepository.save(order)
return {
orderId: order.id,
totalAmount: order.totalAmount,
status: order.status,
estimatedDelivery: this.calculateEstimatedDelivery(order.shippingMethod)
}
},
resultValidator: async (result, context) => {
const errors = []
if (!result.orderId) {
errors.push('订单ID生成失败')
}
if (result.totalAmount <= 0) {
errors.push('订单金额无效')
}
return {
isValid: errors.length === 0,
errors
}
}
})
// 确认订单命令处理器
const ConfirmOrderCommandHandler = this.architecture.applicationCore.defineCommandHandler({
commandType: 'ConfirmOrderCommand',
validator: async (command, context) => {
const errors = []
if (!command.orderId) {
errors.push('订单ID不能为空')
}
return {
isValid: errors.length === 0,
errors
}
},
aggregateLoader: async (command, context, dependencies) => {
const order = await dependencies.orderRepository.findById(command.orderId)
if (!order) {
throw new Error('订单不存在')
}
return order
},
executor: async (aggregate, command, context, dependencies) => {
// 验证订单一致性
await dependencies.orderDomainService.execute(
'validateOrderConsistency',
{ ...context, ...dependencies },
{ orderId: command.orderId }
)
// 确认订单
const result = aggregate.applyBusinessRule('confirmOrder', {
confirmedBy: command.confirmedBy,
confirmationNotes: command.notes
})
return result
},
aggregateSaver: async (aggregate, context, dependencies) => {
await dependencies.orderRepository.save(aggregate)
}
})
// 获取订单查询处理器
const GetOrderQueryHandler = this.architecture.applicationCore.defineQueryHandler({
queryType: 'GetOrderQuery',
validator: async (query, context) => {
const errors = []
if (!query.orderId) {
errors.push('订单ID不能为空')
}
return {
isValid: errors.length === 0,
errors
}
},
permissionChecker: async (query, context, dependencies) => {
// 检查用户是否有权限查看该订单
const order = await dependencies.orderRepository.findById(query.orderId)
return order && (
order.customerId === context.userId ||
context.userRoles.includes('admin')
)
},
executor: async (query, context, dependencies) => {
const order = await dependencies.orderRepository.findById(query.orderId)
if (!order) {
throw new Error('订单不存在')
}
return {
id: order.id,
customerId: order.customerId,
items: order.items,
subtotal: order.subtotal,
shippingCost: order.shippingCost,
taxAmount: order.taxAmount,
totalAmount: order.totalAmount,
status: order.status,
shippingAddress: order.shippingAddress,
createdAt: order.createdAt,
confirmedAt: order.confirmedAt
}
},
resultPostProcessor: async (result, query, context, dependencies) => {
// 添加额外信息
if (context.userRoles.includes('admin')) {
// 管理员可以看到更多信息
const paymentInfo = await dependencies.paymentService.getPaymentInfo(result.id)
result.paymentInfo = paymentInfo
}
return result
}
})
}
calculateEstimatedDelivery(shippingMethod) {
const now = new Date()
const deliveryDays = {
'standard': 7,
'express': 3,
'overnight': 1
}
const days = deliveryDays[shippingMethod] || 7
const estimatedDelivery = new Date(now.getTime() + days * 24 * 60 * 60 * 1000)
return estimatedDelivery
}
}
📚 最佳实践总结
- 依赖方向:确保依赖只从外层指向内层
- 层次隔离:每层只与相邻层交互,不能跨层调用
- 接口抽象:内层定义接口,外层实现具体逻辑
- 领域纯净:核心领域逻辑不依赖任何外部技术
- 测试隔离:通过依赖注入实现单元测试隔离
- 事件驱动:使用领域事件实现层间解耦
- 配置外部化:将配置和环境相关代码放在最外层
- 关注分离:每层专注于自己的职责
通过掌握洋葱架构,您将能够构建高度解耦、可测试、可维护的企业级应用系统。