Go 语言在 DDD 中关于依赖注入和并发处理的最佳实践

我来详细解释 Go 语言在 DDD 中关于依赖注入和并发处理的最佳实践。

// 1. 依赖注入实现
package main

import (
    "context"
    "sync"
)

// 依赖注入容器
type Container struct {
    services map[string]interface{}
    mutex    sync.RWMutex
}

func NewContainer() *Container {
    return &Container{
        services: make(map[string]interface{}),
    }
}

// 注册服务
func (c *Container) Register(name string, service interface{}) {
    c.mutex.Lock()
    defer c.mutex.Unlock()
    c.services[name] = service
}

// 获取服务
func (c *Container) Get(name string) interface{} {
    c.mutex.RLock()
    defer c.mutex.RUnlock()
    return c.services[name]
}

// 服务接口定义
type OrderRepository interface {
    Save(ctx context.Context, order *Order) error
    FindByID(ctx context.Context, id string) (*Order, error)
}

type OrderService interface {
    CreateOrder(ctx context.Context, order *Order) error
    ProcessOrder(ctx context.Context, orderID string) error
}

// 服务实现
type orderService struct {
    repo OrderRepository
    eventBus EventBus
}

// 使用构造函数注入依赖
func NewOrderService(repo OrderRepository, eventBus EventBus) OrderService {
    return &orderService{
        repo: repo,
        eventBus: eventBus,
    }
}

// 2. 并发处理实现
// 工作池模式处理订单
type OrderProcessor struct {
    workers    int
    jobs       chan *Order
    results    chan error
    orderService OrderService
}

func NewOrderProcessor(workers int, orderService OrderService) *OrderProcessor {
    return &OrderProcessor{
        workers:      workers,
        jobs:        make(chan *Order, workers),
        results:     make(chan error, workers),
        orderService: orderService,
    }
}

func (p *OrderProcessor) Start(ctx context.Context) {
    wg := &sync.WaitGroup{}
    
    // 启动工作池
    for i := 0; i < p.workers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for order := range p.jobs {
                select {
                case <-ctx.Done():
                    return
                default:
                    err := p.processOrder(ctx, order)
                    p.results <- err
                }
            }
        }()
    }
    
    // 等待所有工作完成
    go func() {
        wg.Wait()
        close(p.results)
    }()
}

func (p *OrderProcessor) processOrder(ctx context.Context, order *Order) error {
    return p.orderService.ProcessOrder(ctx, order.ID)
}

// 3. 领域事件的并发处理
type EventHandler func(ctx context.Context, event Event) error

type EventBus struct {
    handlers map[string][]EventHandler
    mutex    sync.RWMutex
}

func NewEventBus() *EventBus {
    return &EventBus{
        handlers: make(map[string][]EventHandler),
    }
}

func (b *EventBus) Subscribe(eventType string, handler EventHandler) {
    b.mutex.Lock()
    defer b.mutex.Unlock()
    b.handlers[eventType] = append(b.handlers[eventType], handler)
}

func (b *EventBus) Publish(ctx context.Context, event Event) {
    b.mutex.RLock()
    handlers := b.handlers[event.Type()]
    b.mutex.RUnlock()
    
    // 并发处理所有事件处理器
    wg := &sync.WaitGroup{}
    for _, handler := range handlers {
        wg.Add(1)
        go func(h EventHandler) {
            defer wg.Done()
            if err := h(ctx, event); err != nil {
                // 处理错误
            }
        }(handler)
    }
    wg.Wait()
}

// 4. 应用示例
func main() {
    // 创建依赖注入容器
    container := NewContainer()
    
    // 注册服务
    container.Register("orderRepo", NewOrderRepository())
    container.Register("eventBus", NewEventBus())
    
    // 创建订单服务
    orderService := NewOrderService(
        container.Get("orderRepo").(OrderRepository),
        container.Get("eventBus").(*EventBus),
    )
    
    // 创建订单处理器
    processor := NewOrderProcessor(5, orderService)
    
    // 启动处理
    ctx := context.Background()
    processor.Start(ctx)
}

让我解释一下关键点:

1、依赖注入的最佳实践:

  • 使用接口而不是具体类型
type Service interface {
    DoSomething() error
}

type Handler struct {
    service Service  // 使用接口
}
  •  通过构造函数注入依赖
func NewHandler(service Service) *Handler {
    return &Handler{service: service}
}

 

  • 使用依赖注入容器管理服务生命周期
  • 支持可测试性,便于mock
  • 避免全局状态和单例

2、并发处理的考虑:

  • 使用 context 控制超时和取消
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
  • 合理使用goroutine池避免资源耗尽 
    pool := make(chan struct{}, maxGoroutines)
  • 使用互斥锁保护共享资源 
    var mu sync.RWMutex
    mu.Lock()
    defer mu.Unlock()
  • 正确处理channel的关闭 
    defer close(resultChan)

关键建议:

1、依赖注入:

  • 始终面向接口编程
  • 使用构造函数注入依赖
  • 避免在构造函数中进行复杂操作
  • 考虑使用依赖注入框架(如 wire)

2、并发处理:

  • 始终使用 context 进行超时控制
  • 正确处理 goroutine 的生命周期
  • 使用适当的并发原语(Mutex, RWMutex, WaitGroup等)
  • 考虑使用工作池模式处理并发任务
  • 正确处理错误传播

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值