架构设计对比:MVC、MVP、MVVM与DDD在多语言源码中的展现

架构设计对比:MVC、MVP、MVVM与DDD在多语言代码里的体现

MVC分层架构设计概览

模型-视图-控制器(Model-View-Controller,简称MVC)是一种经典的软件架构设计,通过分层来实现各个部分的解耦,让系统结构清晰且易于维护,具有不错的可扩展性。MVC适用于需要明确区分用户界面、业务逻辑和数据管理的应用场景。随着MVC的发展,衍生出了MVP、MVVM以及领域驱动设计(DDD)等架构,这些架构都是为了让复杂的系统变得更简单,方便人们理解。
![https://img2024.cnblogs.com/blog/2285565/202504/2285565-20250401122153379-1065890830.png]

MVC结构图形示例(以Web后端开发为例)

用户发起请求后,流程如下:

    用户请求  
      |  
      v
+---------+       +-----------+      +-----------+
|  View   |  <--- | Controller| ---> |   Model   | 
+---------+       +-----------+      +-----------+
    ^                                      v
    |            Model数据映射到View         |
    ****--------------------------------****

MVC各层职责

  • 视图层(View):负责处理用户界面的展示以及用户输入的事件。
  • 控制器层(Controller):接收用户的请求,协调模型层和视图层之间的工作。
  • 模型层(Model):封装业务逻辑和数据结构。

MVC是一种软件分层设计模式,目的是让各个层级之间解耦,使代码更清晰易维护。常用来和MVP、MVVM以及DDD分层架构做对比,下面会详细分析这些架构。MVC不同语言源码实现:https://github.com/microwind/design-patterns/tree/main/mvx/mvc

MVC分层架构与DDD分层架构对比

MVC以实现界面与数据的分离为主要目标,着重于快速开发;DDD则是以领域模型驱动为核心思想,专注于复杂业务系统的可持续架构设计。

DDD结构图形示例

    +--------------------+
    |     用户界面层       |
    |   User Interface   |
    |   含Controller/UI   |
    +--------------------+
              |
              v
    +--------------------+
    |      应用服务层      |
    |  Application Layer |
    |   含Service/DTO    |
    +--------------------+
              |
              v
    +--------------------+
    |       领域层        |
    |    Domain Layer    |
    |   含Model/Service  |
    +--------------------+
              |
              v
    +----------------------+
    |       基础设施层       |
    | Infrastructure Layer |
    | 含Repository/Message |
    +----------------------+

DDD各语言源码:https://github.com/microwind/design-patterns/tree/main/domain-driven-design

MVC与DDD分层架构特点

特性 MVC DDD
主要目标 分离UI、逻辑和数据 解决复杂领域建模问题
核心分层 3层(View、Controller、Model) 4层(UI、应用、领域、基础设施)
适用场景 Web应用、前端交互密集型系统 企业级复杂业务系统(如金融交易、供应链管理)
开发效率 快速原型开发,中小型项目友好 需前期领域建模,适合长期演进的大型项目

MVC与MVP、MVVM的分层架构对比

MVC和MVP总体上有相似之处,但在视图层和模型层是否完全解耦方面存在差异。MVP通过接口隔离实现了完全解耦,而MVC允许视图直接访问模型。MVC和MVVM的本质区别在于数据同步机制:MVVM通过双向绑定实现自动的数据同步,而MVC依赖手动进行状态管理。

MVP(Model-View-Presenter)结构图形

User Input  
    | 
    v        由主持人代理View和Model交互
+---------+      +-----------+       +-----------+
|  View   | <--> | Presenter | <---> |   Model   |
+---------+      +-----------+       +-----------+

1. MVP主要用于前端开发,尤其是界面渲染,当一个界面需要针对多个视图数据进行渲染时,使用MVP比MVC更合适。
2. MVP模式下视图层和模型层隔离,视图层中没有对应的模型概念,数据由主持人代为传递。

MVP各语言源码:https://github.com/microwind/design-patterns/tree/main/mvx/mvp

MVVM(Model-View-ViewModel)

User Input  
    |
    v         将View与Model双向数据绑定
+---------+      +-----------+      +-----------+
|  View   | ---> | ViewModel | <--> |   Model    |
+---------+      +-----------+      +-----------+
                   ^        |
                   |        v
          Data Binding(由Agent监听数据变化)

1. MVVM从视图层触发事件,监听事件来执行数据更新。
2. 通过代理监听数据变化,实现视图的自动更新。

MVVM各语言源码:https://github.com/microwind/design-patterns/tree/main/mvx/mvvm

MVC与MVP、MVVM的分层架构特点

模式 控制流程描述 View与Model耦合度 组件角色
MVC 请求驱动模式
Controller接收View请求→操作Model→Model直接通知View更新;View主动监听Model事件。
存在一定耦合,View直接绑定Model。 Controller处理逻辑;View展示数据;Model管理数据。
MVP 中介者模式:View与Presenter双向交互:用户操作触发事件→Presenter调用Model更新→Presenter通知View更新。 完全解耦,View仅与Presenter交互,Model不直接通知View。 Presenter充当中介者;View仅负责展示;Model管理数据。
MVVM 响应式编程模式:利用数据绑定:View与ViewModel双向绑定,ViewModel操作Model后自动反映在View上。 完全解耦,借助数据绑定技术间接通信。 ViewModel充当桥梁;View为声明式UI层;Model纯数据结构。

MVC是分层架构思想的先驱,后来MVP、MVVM、DDD等才流行开来,可以对比下几种分层代码,理解其中的变迁:https://github.com/microwind/design-patterns/tree/main/mvx

MVC的应用场景

  • Web应用程序(如电商网站、博客系统)
  • 前后端分离项目(RESTful API + 前端框架)
  • 桌面GUI应用(Java Swing、C# WinForms)
  • 移动端应用(Android Activity结构)

MVC的例子(C、Java、JavaScript、Go、Python等)

MVC最早从Smalltalk语言发展而来,后来经过Java、C++、.NET等语言发扬光大,除了传统的面向对象语言可以实现MVC模式,其他各种高级语言都能实现MVC。需要注意的是MVC并非一种技术,而是一种理念。只要秉持这种分层思想,任何语言都能实现MVC理念。

C语言实现MVC

/* 视图层(View)*/
// view.c
#include <stdio.h>
#include "controller.h"

void display_order(Order order) {
    printf("Order ID: %s\nCustomer: %s\nAmount: %.2f\n",
           order.id, order.customer_name, order.amount);
}

/* 控制器层(Controller)*/
// controller.c
#include "controller.h"
#include "repository.h"

void create_order(Order order) {
    save_order(order);
}

Order get_order(char* id) {
    return find_order(id);
}

/* 模型层(Model)*/
// order.h
typedef struct {
    char id[10];
    char customer_name[50];
    float amount;
} Order;

/* 数据访问层(Repository)*/
// repository.c
#include <string.h>
#include "repository.h"

static Order orders[100];
static int count = 0;

void save_order(Order order) {
    orders[count++] = order;
}

Order find_order(char* id) {
    for (int i = 0; i < count; i++) {
        if (strcmp(orders[i].id, id) == 0) {
            return orders[i];
        }
    }
    Order empty = { "", "", 0 };
    return empty;
}

Java语言实现MVC

/* 视图层(View)*/
// Thymeleaf 模板 (orders.html)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
    <h1>订单列表</h1>
    <ul>
        <li th:each="order : ${orders}">
            <span th:text="${order.id}"></span> - 
            <span th:text="${order.customerName}"></span>
        </li>
    </ul>
</body>
</html>

/* 控制器层(Controller)*/
// OrderController.java
@Controller
@RequestMapping("/orders")
public class OrderController {
    private final OrderService service;

    @Autowired
    public OrderController(OrderService service) {
        this.service = service;
    }

    @GetMapping
    public String listOrders(Model model) {
        model.addAttribute("orders", service.getAllOrders());
        return "orders";
    }
}

/* 模型层(Model)*/
// Order.java
@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String customerName;
    private BigDecimal amount;

    // Getters & Setters
}

/* 数据访问层(Repository)*/
// OrderRepository.java
public interface OrderRepository extends JpaRepository<Order, Long> {
    List<Order> findByCustomerName(String name);
}

Go语言实现MVC

/* 视图层(View)*/
// view.go
func RenderOrder(w http.ResponseWriter, order Order) {
    fmt.Fprintf(w, "ID: %s\nCustomer: %s\nAmount: %.2f",
        order.ID, order.CustomerName, order.Amount)
}

/* 控制器层(Controller)*/
// controller.go
func OrderHandler(w http.ResponseWriter, r *http.Request) {
    id := r.URL.Query().Get("id")
    order := repository.GetOrder(id)
    RenderOrder(w, order)
}

/* 模型层(Model)*/
// order.go
type Order struct {
    ID           string
    CustomerName string
    Amount       float64
}

/* 数据访问层(Repository)*/
// repository.go
var orders = make(map[string]Order)

func GetOrder(id string) Order {
    return orders[id]
}

func SaveOrder(order Order) {
    orders[order.ID] = order
}

Python语言实现MVC(Flask)

# 视图层(View)
# templates/orders.html
<html>
<body>
    <h1>Orders</h1>
    <ul>
        {% for order in orders %}
            <li>{{ order.id }} - {{ order.customer_name }}</li>
        {% endfor %}
    </ul>
</body>
</html>

# 控制器层(Controller)
# app.py
from flask import Flask, render_template
from service import OrderService

app = Flask(__name__)
service = OrderService()

@app.route('/orders')
def list_orders():
    orders = service.get_all_orders()
    return render_template('orders.html', orders=orders)

# 模型层(Model)
# order.py
class Order:
    def __init__(self, id, customer_name, amount):
        self.id = id
        self.customer_name = customer_name
        self.amount = amount

# 数据访问层(Repository)
# repository.py
class OrderRepository:
    def __init__(self):
        self.orders = {}

    def save(self, order):
        self.orders[order.id] = order

    def get_all(self):
        return list(self.orders.values())

JavaScript实现 MVC(Express.js)

/* 视图层(View)*/
// views/orders.ejs
<!DOCTYPE html>
<html>
<body>
    <h1>Orders</h1>
    <ul>
        <% orders.forEach(order => { %>
            <li><%= order.id %> - <%= order.customerName %></li>
        <% }) %>
    </ul>
</body>
</html>

/* 控制器层(Controller)*/
// routes/orderRoutes.js
const express = require('express');
const router = express.Router();
const service = require('../services/orderService');

router.get('/orders', async (req, res) => {
    const orders = await service.getAllOrders();
    res.render('orders', { orders });
});

/* 模型层(Model)*/
// models/Order.js
class Order {
    constructor(id, customerName, amount) {
        this.id = id;
        this.customerName = customerName;
        this.amount = amount;
    }
}

/* 数据访问层(Repository)*/
// repositories/orderRepository.js
class OrderRepository {
    constructor() {
        this.db = new Map();
    }

    save(order) {
        this.db.set(order.id, order);
    }

    getAll() {
        return Array.from(this.db.values());
    }
}

JavaScript前端版 MVC

功能:点击按钮增减数值并更新视图。
1. 模型层:CounterModel类封装数据和操作逻辑,包含数值和标题的修改方法。
2. 视图层:CounterView类负责渲染界面,绑定模型数据,根据模型状态更新视图。
3. 控制层:CounterController类作为中间层,绑定视图和模型,监听事件,实现数据和视图的更新。

// Model 类:封装数据逻辑
class CounterModel {
    constructor() {
        // 初始化数据
        this.title = '点击更换标题';
        this.num = 0;
    }

    // 标题操作:增加标题
    changeTitle() {
        this.title = '点击更换标题' + Math.floor(Math.random() * 100);
    }

    // 数据操作方法:增加数值
    increment() {
        this.num++;
    }

    // 数据操作方法:减少数值
    decrement() {
        this.num--;
    }
}

// View 类:处理界面渲染
class CounterView {
    template(data = {}) {
        return `
        <div class="counter">
            <h3 class="title">${data.title}</h3>
            <button class="dec-btn">-</button>
            <span class="num">${data.num}</span>
            <button class="inc-btn">+</button>
        </div>
        `;
    }

    constructor(model, container) {
        this.model = model; // 绑定模型,这是跟MVP最大区别
        this.$container = container;
        this.init();
    }

    // 初始化DOM
    init() {
        this.$container.innerHTML = this.template(this.model);
        this.$titleEl = this.$container.querySelector('.title');
        this.$numEl = this.$container.querySelector('.num');
        this.$incBtn = this.$container.querySelector('.inc-btn');
        this.$decBtn = this.$container.querySelector('.dec-btn');
    }

    // 更新视图方法
    render() {
        // 可以根据数据是否有变化来确定要更新哪个字段
        const data = this.model
        this.$titleEl.textContent = data.title;
        this.$numEl.textContent = data.num;
    }
}

// Controller 类:处理用户输入
class CounterController {
    constructor(model, view) {
        this.model = model;
        this.view = view;
        this.bindEvents();
    }

    // 绑定DOM事件
    bindEvents() {
        this.view.$titleEl.addEventListener('click', () => this.changeTitleHandle());
        this.view.$incBtn.addEventListener('click', () => this.incrementHandle());
        this.view.$decBtn.addEventListener('click', () => this.decrementHandle());
    }

    changeTitleHandle() {
        this.model.changeTitle();
        this.view.render(); // 直接更新视图,不必传递model
    }

    // 事件处理:增加操作
    incrementHandle() {
        this.model.increment();
        this.view.render(); // 直接更新视图,不必传递model
    }

    // 事件处理:减少操作
    decrementHandle() {
        this.model.decrement();
        this.view.render(); // 直接更新视图,不必传递model
    }
}

// 初始化应用
const appContainer = document.body;
const model = new CounterModel();
const view = new CounterView(model, appContainer);
const controller = new CounterController(model, view);

总结

  • MVC 适用于快速开发Web应用,强调职责分离。
  • MVP 适用于对视图和业务逻辑分离要求较高的场景,强调展示层对视图和模型的协调。
  • MVVM 适用于复杂视图与模型交互的应用,利用

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/12548.html

(0)
LomuLomu
上一篇 2025 年 6 月 18 日 下午9:19
下一篇 2025 年 6 月 18 日

相关推荐

  • 2025年最新DataGrip永久破解教程(附激活码/注册码)🔥

    还在为DataGrip的激活问题发愁吗?🤔 本教程将手把手教你如何轻松破解DataGrip至2099年!适用于所有JetBrains全家桶软件(IDEA、PyCharm、Goland等),Windows/Mac/Linux全平台通用哦~ 先睹为快:破解成果展示 先给大家看看最新版本的破解成果截图,成功激活到2099年不是梦!🎉 准备工作:下载DataGrip…

    DataGrip激活码 2025 年 6 月 27 日
    16300
  • 2025最新PyCharm永久破解教程(亲测有效,支持2099年)🔥

    适用于IDEA、PyCharm、DataGrip等Jetbrains全家桶工具!💯 先给大家看看最新PyCharm版本破解成功的截图👇,可以看到已经成功破解到2099年啦!🎉 下面我将用详细的图文教程,手把手教你如何激活PyCharm至2099年。这个方法同样适用于旧版本哦!✨ 无论你是Windows、Mac还是Linux系统 无论你使用什么版本 统统都能激…

    2025 年 6 月 2 日
    41000
  • 2025年最新DataGrip永久破解教程(附激活码/注册码)🔥

    适用于JetBrains全家桶(IDEA、PyCharm、DataGrip、GoLand等)的终极破解方案✨ 先给大家看看破解成果🎉 成功激活至2099年,一劳永逸!👇 下面将手把手教你如何完成DataGrip的永久激活,该方法同样适用于旧版本哦~ 💻 无论你是Windows、Mac还是Linux系统,都能完美适配! 🌈 第一步:获取DataGrip安装包 …

    2025 年 6 月 12 日
    13600
  • 高效算法中的优先队列甄选

    文章标题: 优先队列在算法问题中的巧妙应用 目录 一、1046.最后的石头重量计算 二、703. 数据流里的第 K 大元素 三、692. 前 K 个高频词语 四、295. 数据流的中位数求解 一、1046.最后的石头重量计算 题目链接:1046.最后的石头重量题目描述:![ ](https://i-blog.csdnimg.cn/direct/16f1995…

    2025 年 7 月 9 日
    4500
  • 2025年最新PyCharm永久破解教程(附激活码/注册码)🔥

    适用于IDEA、PyCharm、DataGrip等Jetbrains全家桶工具!💯 先给大家看看最新PyCharm版本破解成功的截图👇,可以看到已经成功激活到2099年啦!🎉 下面我将用详细的图文教程,手把手教你如何永久激活PyCharm至2099年✨ 这个方法同样适用于旧版本哦!无论是:- Windows/Mac/Linux系统 💻- 任何PyCharm版…

    PyCharm激活码 2025 年 6 月 26 日
    1.2K00

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信