找回密码
 立即注册
首页 业界区 业界 Go后端架构探索: MVC 与 DDD 分层架构有何不同? ...

Go后端架构探索: MVC 与 DDD 分层架构有何不同?

届表 2025-6-6 14:53:17
Go语言 MVC 与 DDD 分层架构详细对比

MVC和DDD是后台开发两种流行的分层架构思想,MVC(Model-View-Controller)是一种设计模式,主要用于分离用户界面、业务逻辑和数据模型,便于分层解耦,而DDD(领域驱动设计)则是一种架构方法论,旨在通过构建业务领域模型来解决复杂系统中的设计和维护难题。
在Java领域,很多系统逐渐由MVC逐渐转为DDD,但在Go、Python、NodeJS等语言,秉持简单高效的理念,MVC依然是主流架构。下面基于Go语言来具体探讨下MVC和DDD两种目录结构的区别。
1.png

MVC 图形结构
  1. +------------------+
  2. |      View        | 用户界面层:负责数据展示和用户交互(如HTML页面、API响应)
  3. +------------------+
  4. |   Controller     | 控制层:处理用户请求,调用Service逻辑,协调Model与View
  5. +------------------+
  6. |      Model       | 模型层:包含数据对象(如数据库表结构)和部分业务逻辑(常分散在Service层)
  7. +------------------+
复制代码
DDD 图形结构
  1. +--------------------+
  2. |   用户界面层(UI)    | 负责用户交互和展示(如REST API、Web界面)
  3. +--------------------+
  4. | 应用层(Application)| 编排业务流程(如调用领域服务、事务管理),不包含核心业务规则
  5. +--------------------+
  6. |  领域层(Domain)    | 核心业务逻辑层:包含聚合根、实体、值对象、领域服务等,内聚业务规则
  7. +--------------------+
  8. |      基础设施层      | 提供技术实现(如数据库访问、消息队列、外部API)
  9. |  (Infrastructure) |
  10. +--------------------+
复制代码
MVC 与 DDD 的主要区别:

1. 代码组织逻辑
MVC 按技术功能分层(Controller/Service/DAO),关注技术实现;DDD 按业务领域划分模块(如订单域、支付域),以限界上下文隔离核心业务逻辑。
2. 业务逻辑载体
MVC 通常采用贫血模型,数据(Model)与行为(Service)分离,逻辑分散导致维护成本高;DDD 通过聚合根、领域服务实现充血模型,业务逻辑内聚于领域层,增强可扩展性。
3. 适用性与成本
MVC 开发成本低,适合需求稳定的中小型系统;DDD 需前期领域建模和统一语言,适用于业务复杂、需长期演进的大型系统,但团队需具备领域抽象能力。例如,电商促销规则用 DDD 可避免逻辑散落在多个 Service 中。
Go语言 MVC 目录结构

MVC主要分为三层:视图、控制器、模型。
  1. gin-order/
  2. ├── cmd
  3. │   └── main.go                  # 应用入口,启动 Gin 引擎
  4. ├── internal
  5. │   ├── controllers              # 控制器层(处理 HTTP 请求),也可以叫handlers
  6. │   │   └── order
  7. │   │       └── order_controller.go  # Order 模块的控制器
  8. │   ├── services                 # 服务层(业务逻辑处理)
  9. │   │   └── order
  10. │   │       └── order_service.go       # Order 模块的服务实现
  11. │   ├── repository               # 数据访问层(与数据库交互)
  12. │   │   └── order
  13. │   │       └── order_repository.go    # Order 模块的数据访问接口及实现
  14. │   ├── models                   # 模型层(数据结构定义)
  15. │   │   └── order
  16. │   │       └── order.go               # Order 模块的数据模型
  17. │   ├── middleware               # 中间件(如鉴权、日志、请求拦截)
  18. │   │   ├── logging.go             # 日志中间件
  19. │   │   └── auth.go                # 鉴权中间件
  20. │   └── config                   # 配置模块(数据库、服务器等配置)
  21. │       └── config.go                # 应用与环境配置
  22. ├── pkg                          # 公共工具包(如响应包装工具)
  23. │   └── response.go              # 响应处理工具方法
  24. ├── web                          # 前端资源(模板与静态资源)
  25. │   ├── static                   # 静态资源(CSS、JS、图片)
  26. │   └── templates                # 模板文件(HTML模板)
  27. │       └── order.tmpl           # Order 模块的视图模板(如果需要渲染HTML)
  28. ├── go.mod                       # Go 模块管理文件
  29. └── go.sum                       # Go 模块依赖版本锁定
复制代码
Go语言 DDD 目录结构

DD主要分为四层:界面、应用、领域、基础。
  1. go-web/
  2. │── cmd/
  3. │   └── main.go               # 应用入口
  4. │── internal/
  5. │   ├── application/          # 应用层(协调领域逻辑,处理业务用例)
  6. │   │   ├── services/         # 服务层,业务逻辑目录
  7. │   │   │   └── order_service.go # 订单应用服务,调用领域层业务逻辑
  8. │   ├── domain/               # 领域层(核心业务逻辑和接口定义)
  9. │   │   ├── order/            # 订单聚合
  10. │   │   │   ├── order.go      # 订单实体(聚合根),包含核心业务逻辑
  11. │   │   ├── repository/       # 通用仓库接口
  12. │   │   │   ├── repository.go # 通用仓库接口(通用 CRUD 操作)
  13. │   │   │   └── order_repository.go # 订单仓储接口,定义对订单数据的操作
  14. │   ├── infrastructure/       # 基础设施层(实现领域层定义的接口)
  15. │   │   ├── repository/       # 仓储实现
  16. │   │   │   └── order_repository_impl.go  # 订单仓储实现,具体的订单数据存储
  17. │   └── interfaces/           # 接口层(处理外部请求,如HTTP接口)
  18. │   │   ├── handlers/         # HTTP 处理器
  19. │   │   │  └── order_handler.go # 订单相关的HTTP处理器
  20. │   │   └── routes/
  21. │   │   │   ├── router.go     # 基础路由工具设置
  22. │   │   │   └── order-routes.go # 订单路由地址配置
  23. │   │   │   └── order-routes-test.go # 订单路由测试
  24. │   └── middleware/           # 中间件(例如:鉴权、拦截、认证等)
  25. │   │   └── logging.go        # 日志中间件
  26. │   ├── config/               # 服务相关配置
  27. │   │   └── server_config.go  # 服务器配置(如端口、超时设置等)
  28. │── pkg/                      # 可复用的公共库
  29. │   └── utils/                # 工具类(例如:日志、日期处理等)
复制代码
Go语言 MVC 代码实现

源码:https://github.com/microwind/design-patterns/tree/main/mvx/mvc/gin-mvc
  1. Controller(接口层) → Service(业务逻辑层) → Repository(数据访问层) → Model(数据模型)
复制代码
分层代码


  • 控制器层(Controller)
  1. // internal/controller/order/order.go
  2. package order
  3. import (
  4.     "net/http"
  5.     "strconv"
  6.     "github.com/gin-gonic/gin"
  7.     "github.com/gin-order/internal/model"
  8.     "github.com/gin-order/internal/service/order"
  9.     "github.com/gin-order/internal/pkg/response"
  10. )
  11. type OrderController struct {
  12.     service *order.OrderService
  13. }
  14. func NewOrderController(service *order.OrderService) *OrderController {
  15.     return &OrderController{service: service}
  16. }
  17. func (c *OrderController) GetOrder(ctx *gin.Context) {
  18.     idStr := ctx.Param("id")
  19.     id, _ := strconv.ParseUint(idStr, 10, 64)
  20.    
  21.     order, err := c.service.GetOrderByID(uint(id))
  22.     if err != nil {
  23.         response.Error(ctx, http.StatusNotFound, "Order not found")
  24.         return
  25.     }
  26.    
  27.     response.Success(ctx, order)
  28. }
  29. func (c *OrderController) CreateOrder(ctx *gin.Context) {
  30.     var req model.Order
  31.     if err := ctx.ShouldBindJSON(&req); err != nil {
  32.         response.Error(ctx, http.StatusBadRequest, "Invalid request")
  33.         return
  34.     }
  35.    
  36.     if err := c.service.CreateOrder(&req); err != nil {
  37.         response.Error(ctx, http.StatusInternalServerError, "Create failed")
  38.         return
  39.     }
  40.    
  41.     response.Success(ctx, req)
  42. }
复制代码

  • 路由配置
  1. // cmd/server/main.go
  2. package main
  3. import (
  4.     "github.com/gin-gonic/gin"
  5.     "github.com/gin-order/internal/controller/order"
  6.     "github.com/gin-order/internal/pkg/database"
  7.     "github.com/gin-order/internal/repository/order"
  8.     "github.com/gin-order/internal/service/order"
  9. )
  10. func main() {
  11.     // 初始化数据库
  12.     db := database.NewGORM()
  13.    
  14.     // 依赖注入
  15.     orderRepo := order_repo.NewMySQLOrderRepository(db)
  16.     orderService := order_service.NewOrderService(orderRepo)
  17.     orderController := order_controller.NewOrderController(orderService)
  18.    
  19.     // 创建路由
  20.     r := gin.Default()
  21.    
  22.     // 注册中间件
  23.     r.Use(middleware.Logger())
  24.    
  25.     // 路由分组
  26.     apiGroup := r.Group("/api")
  27.     {
  28.         orderGroup := apiGroup.Group("/orders")
  29.         {
  30.             orderGroup.GET("/:id", orderController.GetOrder)
  31.             orderGroup.POST("", orderController.CreateOrder)
  32.         }
  33.     }
  34.    
  35.     // 启动服务
  36.     r.Run(":8080")
  37. }
复制代码

  • 服务层(Service)
  1. // internal/service/order/service.go
  2. package order
  3. import (
  4.     "github.com/gin-order/internal/model"
  5.     "github.com/gin-order/internal/repository/order"
  6. )
  7. type OrderService struct {
  8.     repo order.OrderRepository
  9. }
  10. func NewOrderService(repo order.OrderRepository) *OrderService {
  11.     return &OrderService{repo: repo}
  12. }
  13. func (s *OrderService) GetOrderByID(id uint) (*model.Order, error) {
  14.     return s.repo.FindByID(id)
  15. }
  16. func (s *OrderService) CreateOrder(order *model.Order) error {
  17.     return s.repo.Create(order)
  18. }
复制代码

  • 数据访问层(Repository)
  1. // internal/repository/order/interface.go
  2. package order
  3. import "github.com/gin-order/internal/model"
  4. type OrderRepository interface {
  5.     FindByID(id uint) (*model.Order, error)
  6.     Create(order *model.Order) error
  7.     FindByStatus(status string) ([]model.Order, error)
  8. }
复制代码
  1. // internal/repository/order/mysql.go
  2. package order
  3. import (
  4.     "gorm.io/gorm"
  5.     "github.com/gin-order/internal/model"
  6. )
  7. type MySQLOrderRepository struct {
  8.     db *gorm.DB
  9. }
  10. func NewMySQLOrderRepository(db *gorm.DB) OrderRepository {
  11.     return &MySQLOrderRepository{db: db}
  12. }
  13. func (r *MySQLOrderRepository) FindByID(id uint) (*model.Order, error) {
  14.     var order model.Order
  15.     if err := r.db.First(&order, id).Error; err != nil {
  16.         return nil, err
  17.     }
  18.     return &order, nil
  19. }
  20. func (r *MySQLOrderRepository) Create(order *model.Order) error {
  21.     return r.db.Create(order).Error
  22. }
  23. func (r *MySQLOrderRepository) FindByStatus(status string) ([]model.Order, error) {
  24.     var orders []model.Order
  25.     if err := r.db.Where("status = ?", status).Find(&orders).Error; err != nil {
  26.         return nil, err
  27.     }
  28.     return orders, nil
  29. }
复制代码

  • 模型层(Model)
  1. // internal/model/order.go
  2. package model
  3. import "time"
  4. type Order struct {
  5.     OrderID     uint      `gorm:"primaryKey;column:order_id"`
  6.     OrderNo     string    `gorm:"uniqueIndex;column:order_no"`
  7.     UserID      uint      `gorm:"index;column:user_id"`
  8.     OrderName   string    `gorm:"column:order_name"`
  9.     Amount      float64   `gorm:"type:decimal(10,2);column:amount"`
  10.     Status      string    `gorm:"column:status"`
  11.     CreatedAt   time.Time `gorm:"column:created_at"`
  12.     UpdatedAt   time.Time `gorm:"column:updated_at"`
  13. }
  14. func (Order) TableName() string {
  15.     return "orders"
  16. }
复制代码
Go语言 MVC 最佳实践

接口隔离原则

Repository 层通过接口定义,支持多种数据库实现
  1. // 可轻松切换为 Mock 实现
  2. type MockOrderRepository struct {}
  3. func (m *MockOrderRepository) FindByID(id uint) (*model.Order, error) {
  4.     return &model.Order{OrderNo: "mock-123"}, nil
  5. }
复制代码
统一响应格式
  1. // pkg/response/response.go
  2. func Success(c *gin.Context, data interface{}) {
  3.     c.JSON(http.StatusOK, gin.H{
  4.         "code":    0,
  5.         "message": "success",
  6.         "data":    data,
  7.     })
  8. }
复制代码
中间件链
  1. // 全局中间件
  2. r.Use(gin.Logger(), gin.Recovery())
  3. // 路由组中间件
  4. adminGroup := r.Group("/admin", middleware.AuthJWT())
复制代码
数据库迁移

使用 GORM AutoMigrate:
  1. db.AutoMigrate(&model.Order{})
复制代码
Go语言 DDD 代码实现与最佳实践

源码:https://github.com/microwind/design-patterns/tree/main/domain-driven-design/go-web
1. 关注领域模型

DDD 强调领域模型的构建,使用 聚合(Aggregate)实体(Entity)值对象(Value Object) 组织业务逻辑。
在 Go 语言中,通常使用 struct 定义实体和值对象:
  1. // 实体(Entity)
  2. type User struct {
  3.     ID   int
  4.     Name string
  5. }
复制代码
2. 分层架构

DDD 通常采用 分层架构,Go 语言项目可以遵循如下结构:

  • 领域层(Domain Layer):核心业务逻辑,如 domain 目录下的实体和聚合。
  • 应用层(Application Layer):用例(Use Cases)和业务流程编排。
  • 基础设施层(Infrastructure Layer):数据库、缓存、外部 API 适配等。
  • 接口层(Interface Layer):提供 HTTP、gRPC 或 CLI 接口。
3. 依赖倒置(Dependency Inversion)

领域层不应直接依赖基础设施,而是通过 接口(Interface) 进行依赖倒置。
注:DDD架构核心就是依赖倒置(DIP),Domain是最核心的内层,仅定义业务规则和接口抽象,其他层级依赖Domain实现,Domain不依赖任何外部实现。在六边形架构(Hexagonal Architecture)中,领域层位于核心,其他层级(如应用层、基础设施层)通过实现领域层定义的接口来提供具体技术细节(如数据库操作、API 调用),从而达成领域与技术实现的解耦。
  1. // 领域层:定义接口
  2. type UserRepository interface {
  3.     GetByID(id int) (*User, error)
  4. }
复制代码
  1. // 基础设施层:数据库实现
  2. type userRepositoryImpl struct {
  3.     db *sql.DB
  4. }
  5. func (r *userRepositoryImpl) GetByID(id int) (*User, error) {
  6.     // 数据库查询逻辑
  7. }
复制代码
4. 聚合(Aggregate)管理

聚合根(Aggregate Root)管理整个聚合的生命周期:
  1. type Order struct {
  2.     ID      int
  3.     Items   []OrderItem
  4.     Status  string
  5. }
  6. func (o *Order) AddItem(item OrderItem) {
  7.     o.Items = append(o.Items, item)
  8. }
复制代码
5. 应用服务(Application Service)

应用服务封装领域逻辑,避免外部直接操作领域对象:
  1. type OrderService struct {
  2.     repo OrderRepository
  3. }
  4. func (s *OrderService) CreateOrder(userID int, items []OrderItem) (*Order, error) {
  5.     order := Order{UserID: userID, Items: items, Status: "Pending"}
  6.     return s.repo.Save(order)
  7. }
复制代码
6. 事件驱动(Event-Driven)

使用 领域事件(Domain Events) 进行解耦,在 Go 语言中可通过 ChannelPub/Sub 实现:
[code]type OrderCreatedEvent struct {    OrderID int}def publishEvent(event OrderCreatedEvent) {    go func() {        eventChannel

相关推荐

您需要登录后才可以回帖 登录 | 立即注册