设计模式综合应用:电商订单系统实战案例
引言
设计模式是软件设计中的基石,掌握设计模式可以帮助我们编写更加可维护、可扩展和可复用的代码。本文将通过一个电商订单系统的实战案例,展示如何综合运用多种设计模式来解决实际业务问题。
一、需求分析
1.1 业务背景
假设我们需要构建一个电商平台的订单系统,主要功能包括:
- 创建订单
- 订单支付
- 订单状态管理
- 订单取消与退款
- 订单查询
1.2 核心需求
- 订单创建:支持多种商品类型、优惠活动、库存检查
- 支付方式:支持微信支付、支付宝、银行卡等多种支付方式
- 状态流转:订单状态包括待支付、已支付、待发货、已发货、已完成、已取消
- 异常处理:支付失败、库存不足、网络异常等场景
1.3 非功能需求
- 高可用性:支持高并发场景
- 可扩展性:方便添加新的支付方式和商品类型
- 可维护性:代码结构清晰,易于理解和维护
二、架构设计
2.1 整体架构
┌─────────────────────────────────────────────────────────────┐ │ 订单系统架构 │ ├─────────────────────────────────────────────────────────────┤ │ Controller层 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │OrderCtrl │ │PayCtrl │ │QueryCtrl │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ ├───────┼─────────────┼─────────────┼────────────────────────┤ │ Service层 │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │OrderService │ │PaymentService│ │InventoryService│ │ │ └────┬─────────┘ └────┬─────────┘ └────┬───────────┘ │ ├───────┼─────────────────┼─────────────────┼──────────────────┤ │ Repository层 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │OrderRepo │ │PayRepo │ │StockRepo │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ ├───────┴─────────────┴─────────────┴────────────────────────┤ │ Database │ │ ┌─────────────────────────────┐ │ │ │ MySQL │ Redis │ Kafka│ │ │ └─────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘2.2 设计模式选择
根据需求分析,我们将使用以下设计模式:
| 设计模式 | 应用场景 | 解决的问题 |
|---|---|---|
| 工厂模式 | 支付方式创建 | 解耦支付方式的创建和使用 |
| 策略模式 | 支付算法 | 支持不同的支付算法 |
| 状态模式 | 订单状态流转 | 管理订单状态的复杂转换 |
| 观察者模式 | 订单事件通知 | 订单状态变化时通知相关服务 |
| 门面模式 | 订单服务 | 简化客户端调用 |
| 模板方法 | 支付流程 | 定义支付流程骨架 |
三、核心代码实现
3.1 工厂模式:支付方式工厂
package payment import "errors" type PaymentMethod interface { Pay(amount float64) error GetMethodName() string } type PaymentFactory struct{} func (f *PaymentFactory) CreatePayment(method string) (PaymentMethod, error) { switch method { case "wechat": return NewWeChatPayment(), nil case "alipay": return NewAlipayPayment(), nil case "bank": return NewBankPayment(), nil default: return nil, errors.New("unsupported payment method") } } type WeChatPayment struct{} func NewWeChatPayment() *WeChatPayment { return &WeChatPayment{} } func (w *WeChatPayment) Pay(amount float64) error { // 调用微信支付API return nil } func (w *WeChatPayment) GetMethodName() string { return "wechat" } type AlipayPayment struct{} func NewAlipayPayment() *AlipayPayment { return &AlipayPayment{} } func (a *AlipayPayment) Pay(amount float64) error { // 调用支付宝支付API return nil } func (a *AlipayPayment) GetMethodName() string { return "alipay" }3.2 策略模式:支付策略
package payment type PaymentStrategy interface { Execute(amount float64, orderID string) (bool, error) } type DefaultPaymentStrategy struct{} func (d *DefaultPaymentStrategy) Execute(amount float64, orderID string) (bool, error) { factory := &PaymentFactory{} method, _ := factory.CreatePayment("wechat") return method.Pay(amount) == nil, nil } type QuickPayStrategy struct{} func (q *QuickPayStrategy) Execute(amount float64, orderID string) (bool, error) { if amount < 100 { factory := &PaymentFactory{} method, _ := factory.CreatePayment("wechat") return method.Pay(amount) == nil, nil } return false, errors.New("quick pay only supports amount less than 100") } type PaymentContext struct { strategy PaymentStrategy } func (c *PaymentContext) SetStrategy(strategy PaymentStrategy) { c.strategy = strategy } func (c *PaymentContext) ExecutePayment(amount float64, orderID string) (bool, error) { return c.strategy.Execute(amount, orderID) }3.3 状态模式:订单状态管理
package order import "errors" type OrderState interface { Pay(order *Order) error Ship(order *Order) error Complete(order *Order) error Cancel(order *Order) error GetStateName() string } type Order struct { ID string Amount float64 State OrderState } type PendingPaymentState struct{} func (p *PendingPaymentState) Pay(order *Order) error { order.State = &PaidState{} return nil } func (p *PendingPaymentState) Ship(order *Order) error { return errors.New("cannot ship before payment") } func (p *PendingPaymentState) Complete(order *Order) error { return errors.New("cannot complete before payment") } func (p *PendingPaymentState) Cancel(order *Order) error { order.State = &CancelledState{} return nil } func (p *PendingPaymentState) GetStateName() string { return "pending_payment" } type PaidState struct{} func (p *PaidState) Pay(order *Order) error { return errors.New("already paid") } func (p *PaidState) Ship(order *Order) error { order.State = &ShippedState{} return nil } func (p *PaidState) Complete(order *Order) error { return errors.New("cannot complete before shipping") } func (p *PaidState) Cancel(order *Order) error { order.State = &RefundedState{} return nil } func (p *PaidState) GetStateName() string { return "paid" }3.4 观察者模式:订单事件通知
package order type OrderObserver interface { Update(order *Order, event string) } type InventoryObserver struct{} func (i *InventoryObserver) Update(order *Order, event string) { if event == "order_created" { // 扣减库存 } else if event == "order_cancelled" { // 恢复库存 } } type NotificationObserver struct{} func (n *NotificationObserver) Update(order *Order, event string) { if event == "order_created" { // 发送订单创建通知 } else if event == "order_shipped" { // 发送发货通知 } } type OrderSubject struct { observers []OrderObserver } func (s *OrderSubject) Attach(observer OrderObserver) { s.observers = append(s.observers, observer) } func (s *OrderSubject) Detach(observer OrderObserver) { for i, obs := range s.observers { if obs == observer { s.observers = append(s.observers[:i], s.observers[i+1:]...) break } } } func (s *OrderSubject) Notify(order *Order, event string) { for _, observer := range s.observers { observer.Update(order, event) } }3.5 门面模式:订单服务
package order type OrderService struct { inventoryService *InventoryService paymentService *PaymentService notificationService *NotificationService } func NewOrderService() *OrderService { return &OrderService{ inventoryService: NewInventoryService(), paymentService: NewPaymentService(), notificationService: NewNotificationService(), } } func (s *OrderService) CreateOrder(request CreateOrderRequest) (*Order, error) { // 1. 检查库存 if err := s.inventoryService.CheckStock(request.Items); err != nil { return nil, err } // 2. 创建订单 order := &Order{ ID: generateOrderID(), Amount: request.TotalAmount, State: &PendingPaymentState{}, } // 3. 扣减库存 if err := s.inventoryService.DeductStock(request.Items); err != nil { return nil, err } // 4. 发送通知 s.notificationService.SendOrderCreatedNotification(order) return order, nil } func (s *OrderService) PayOrder(orderID string, paymentMethod string) error { order, err := s.getOrderByID(orderID) if err != nil { return err } if err := order.State.Pay(order); err != nil { return err } return s.paymentService.ProcessPayment(order, paymentMethod) }3.6 模板方法模式:支付流程
package payment type PaymentTemplate interface { Validate() error Prepare() error Execute() error Complete() error } type AbstractPayment struct{} func (a *AbstractPayment) ProcessPayment(order *Order) error { if err := a.Validate(); err != nil { return err } if err := a.Prepare(); err != nil { return err } if err := a.Execute(); err != nil { a.Rollback() return err } return a.Complete() } func (a *AbstractPayment) Validate() error { return nil } func (a *AbstractPayment) Prepare() error { return nil } func (a *AbstractPayment) Execute() error { return nil } func (a *AbstractPayment) Complete() error { return nil } func (a *AbstractPayment) Rollback() { // 回滚逻辑 } type WeChatPaymentProcess struct { AbstractPayment } func (w *WeChatPaymentProcess) Validate() error { // 验证微信支付参数 return nil } func (w *WeChatPaymentProcess) Execute() error { // 调用微信支付API return nil }四、组合应用示例
4.1 创建订单流程
func CreateOrderExample() { service := NewOrderService() request := CreateOrderRequest{ UserID: "user_001", Items: []OrderItem{{ProductID: "prod_001", Quantity: 2}}, TotalAmount: 299.99, } order, err := service.CreateOrder(request) if err != nil { // 处理错误 } // 订单创建成功,状态为待支付 fmt.Println("Order state:", order.State.GetStateName()) }4.2 支付订单流程
func PayOrderExample(orderID string) { service := NewOrderService() // 使用策略模式选择支付策略 context := &PaymentContext{} order, _ := service.getOrderByID(orderID) if order.Amount < 100 { context.SetStrategy(&QuickPayStrategy{}) } else { context.SetStrategy(&DefaultPaymentStrategy{}) } success, err := context.ExecutePayment(order.Amount, orderID) if err != nil { // 处理错误 } if success { // 更新订单状态 service.PayOrder(orderID, "wechat") } }4.3 订单状态流转
func OrderStateTransitionExample() { order := &Order{ ID: "order_001", Amount: 199.99, State: &PendingPaymentState{}, } // 支付 order.State.Pay(order) fmt.Println("After pay:", order.State.GetStateName()) // 发货 order.State.Ship(order) fmt.Println("After ship:", order.State.GetStateName()) // 完成 order.State.Complete(order) fmt.Println("After complete:", order.State.GetStateName()) }五、设计模式组合策略
5.1 模式协作关系
┌───────────────────┐ │ OrderService │ ← 门面模式 └────────┬──────────┘ │ ┌───────────────────┼───────────────────┐ ▼ ▼ ▼ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │PaymentFactory │ │ OrderState │ │OrderSubject │ │ 工厂模式 │ │ 状态模式 │ │ 观察者模式 │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │ │ │ ▼ ▼ ▼ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │PaymentStrategy│ │ Payment │ │ Observers │ │ 策略模式 │ │ 模板方法模式 │ │ │ └───────────────┘ └───────────────┘ └───────────────┘5.2 设计原则应用
- 单一职责原则:每个类只负责一个功能
- 开闭原则:通过接口和抽象类实现扩展开放、修改关闭
- 依赖倒置原则:依赖抽象而非具体实现
- 接口隔离原则:使用细粒度接口
- 里氏替换原则:子类可以替换父类
- 迪米特法则:减少对象之间的耦合
六、总结
通过综合运用多种设计模式,我们构建了一个结构清晰、易于扩展的电商订单系统。每种设计模式都解决了特定的问题:
- 工厂模式:解耦了支付方式的创建和使用
- 策略模式:支持不同的支付策略
- 状态模式:优雅地管理了订单状态的复杂转换
- 观察者模式:实现了订单事件的解耦通知
- 门面模式:简化了客户端与系统的交互
- 模板方法:定义了支付流程的骨架
在实际项目中,需要根据具体需求选择合适的设计模式组合,避免过度设计。设计模式不是银弹,关键在于理解每种模式的适用场景和权衡。