探索MVC、MVP、MVVM和DDD架構在不同編程語言中的實現差異

MVC與MVP/MVVM/DDD架構對比,不同語言實現

MVC 分層架構設計概述

模型-視圖-控制器(Model-View-Controller,簡稱 MVC)是一種經典軟件架構設計,通過分層解耦,使得系統結構清晰和易于維護,具有良好的可擴展性。MVC 適用于需要清晰分離用戶界面、業務邏輯和數據管理的應用場景。隨著MVC的發展,還衍生出了MVP、MVVM以及領域驅動設計(DDD)等架構,這些都是為了讓龐大的系統變得簡單,易于人們理解。
在這里插入圖片描述

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 分層架構特點

特性MVCDDD
主要目標分離 UI、邏輯和數據解決復雜領域建模問題
核心分層3 層(View、Controller、Model)4 層(UI、應用、領域、基礎設施)
適用場景Web 應用、前端交互密集型系統企業級復雜業務系統(如金融交易、供應鏈管理)
開發效率快速原型開發,中小型項目友好需前期領域建模,適合長期演進的大型項目

MVC與MVP、MVVM的分層架構對比

MVC與MVP總體上一致,只是在View與Model是否完全解耦上有差別。MVP通過接口隔離實現完全解耦,而MVC允許視圖直接訪問模型。MVC與MVVM的本質差異在于數據同步機制:MVVM通過雙向綁定實現自動數據同步,MVC則依賴手動進行狀態管理。

MVP(Model-View-Presenter)結構圖形

User Input  | v        由主持人代理View和Model交互
+---------+      +-----------+       +-----------+
|  View   | <--> | Presenter | <---> |   Model   |
+---------+      +-----------+       +-----------+1. MVP 主要用于前端開發,尤其是界面渲染,當一個界面需要針對多個視圖數據進行渲染時,采用MVP比MVC更合適。
2. MVP 下 View 與 Model 隔離,View 中沒有對應 Model 概念,數據由 Presenter 代為傳遞。

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

MVVM(Model-View-ViewModel)

User Input  |v         將View與Model雙向數據綁定
+---------+      +-----------+      +-----------+
|  View   | ---> | ViewModel | <--> |   Model    |
+---------+      +-----------+      +-----------+^        ||        vData Binding(由Agent監聽數據變化)1. MVVM 從 View 觸發,監聽事件執行數據更新。
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 上。完全解耦,借助數據綁定技術實現 View 與 Model 之間的間接通信。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;@Autowiredpublic OrderController(OrderService service) {this.service = service;}@GetMappingpublic 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           stringCustomerName stringAmount       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 OrderServiceapp = 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 = idself.customer_name = customer_nameself.amount = amount# 數據訪問層(Repository)
# repository.py
class OrderRepository:def __init__(self):self.orders = {}def save(self, order):self.orders[order.id] = orderdef 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();}// 初始化DOMinit() {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.modelthis.$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 ?適用于復雜視圖與模型交互的應用,利用數據綁定機制自動同步視圖和模型的狀態。
  • DDD 適用于復雜業務系統,強調領域建模。
  • 核心優勢:代碼可維護性強,團隊協作效率高。
  • 選型建議:中小型項目優先考慮 MVC,復雜業務系統可結合 DDD。

最后

  • 要用 MVC 嗎? 90% 的 Web 項目都適合 MVC 架構
  • 如何判斷適用性? 如果需求變化主要集中在 UI 和流程的中小型項目,MVC 是最佳選擇
  • 擴展建議:大型項目可在 MVC 基礎上增加 Service 層和 DTO 對象,或者直接采用DDD架構
  • 更多設計與架構源碼: https://github.com/microwind/design-patterns

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/74133.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/74133.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/74133.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一文讀懂 UML:基礎概念與體系框架

UML 圖是一種標準化的建模語言&#xff0c;在軟件開發和系統設計等領域有著廣泛的應用。以下是對 UML 圖各類圖的詳細介紹&#xff1a; 1.用例圖 定義&#xff1a;用例圖是從用戶角度描述系統功能的模型圖&#xff0c;展現了系統的參與者與用例之間的關系。作用&#xff1a;幫…

Spring 及 Spring Boot 條件化注解(15個)完整列表及示例

Spring 及 Spring Boot 條件化注解完整列表及示例 1. 所有條件化注解列表 Spring 和 Spring Boot 提供了以下條件化注解&#xff08;共 15 個&#xff09;&#xff0c;用于在配置類或方法上實現條件化注冊 Bean 或配置&#xff1a; 注解名稱作用來源框架Conditional自定義條件…

【Kafka】深入探討 Kafka 如何保證一致性

文章目錄 Kafka 基本概念回顧?副本角色? 數據寫入一致性?同步副本&#xff08;ISR&#xff09;集合?數據讀取一致性?故障處理與一致性恢復?總結? 在分布式系統領域&#xff0c;數據一致性是至關重要的一環。作為一款高性能的分布式消息隊列系統&#xff0c;Kafka 在設計…

從入門到精通:SQL注入防御與攻防實戰——紅隊如何突破,藍隊如何應對!

引言&#xff1a;為什么SQL注入攻擊依然如此強大&#xff1f; SQL注入&#xff08;SQL Injection&#xff09;是最古老且最常見的Web應用漏洞之一。盡管很多公司和組織都已經采取了WAF、防火墻、數據庫隔離等防護措施&#xff0c;但SQL注入依然在許多情況下能夠突破防線&#…

【算法day27】有效的數獨——請你判斷一個 9 x 9 的數獨是否有效。只需要 根據以下規則 ,驗證已經填入的數字是否有效即可。

36. 有效的數獨 請你判斷一個 9 x 9 的數獨是否有效。只需要 根據以下規則 &#xff0c;驗證已經填入的數字是否有效即可。 數字 1-9 在每一行只能出現一次。 數字 1-9 在每一列只能出現一次。 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。&#xff08;請參考示例…

leetcode 2360. 圖中的最長環 困難

給你一個 n 個節點的 有向圖 &#xff0c;節點編號為 0 到 n - 1 &#xff0c;其中每個節點 至多 有一條出邊。 圖用一個大小為 n 下標從 0 開始的數組 edges 表示&#xff0c;節點 i 到節點 edges[i] 之間有一條有向邊。如果節點 i 沒有出邊&#xff0c;那么 edges[i] -1 。…

PySpur: AI 智能體可視化開發平臺

GitHub&#xff1a;https://github.com/PySpur-Dev/pyspur 更多AI開源軟件&#xff1a;發現分享好用的AI工具、AI開源軟件、AI模型、AI變現 - 小眾AI PySpur是一個開源的輕量級可視化AI智能體工作流構建器&#xff0c;旨在簡化AI系統的開發流程。通過拖拽式界面&#xff0c;用戶…

vcpkg安裝及使用教程,以安裝matio庫解析mat文件為例

vcpkg安裝及使用教程,以安裝matio庫解析mat文件為例 1. vcpkg安裝2 安裝matio三方庫3 將三方庫集成到VS中3.1 全局集成3.2 集成到特定工程4 結語Vcpkg 是微軟開發的一款開源的 C/C++ 包管理工具,旨在簡化 C/C++ 項目依賴庫的安裝和管理。它支持跨平臺(Windows、Linux、macO…

LLM架構解析:NLP基礎(第一部分)—— 模型、核心技術與發展歷程全解析

本專欄深入探究從循環神經網絡&#xff08;RNN&#xff09;到Transformer等自然語言處理&#xff08;NLP&#xff09;模型的架構&#xff0c;以及基于這些模型構建的應用程序。 本系列文章內容&#xff1a; NLP自然語言處理基礎&#xff08;本文&#xff09;詞嵌入&#xff0…

【Rtklib入門指南】2. 使用RTKLIB GUI進行觀測數據分析

數據準備 下載2025年1月1日的香港CORS站數據和觀測星歷&#xff0c;詳情參照如下博客&#xff1a; 使用GAMP_GOOD進行hk數據下載教程-CSDN博客 分析工具 RTKLIB 2.4.3 demo5&#xff08;也可以選用RTKLIB2.4.2&#xff0c;但不建議使用RTKLIB2.4.3&#xff09; 分析流程 …

suse15 sp1使用華為云軟件源yum源zypper源

登錄suse15終端&#xff0c; cd /etc/zypp/repos.d/進入目錄后執行以下命令&#xff1a; zypper ar -fcg https://mirrors.huaweicloud.com/opensuse/distribution/leap/15.1/repo/oss HuaWeiCloud:15.1:OSS zypper ar -fcg https://mirrors.huaweicloud.com/opensuse/distribu…

首屏加載時間優化解決

&#x1f916; 作者簡介&#xff1a;水煮白菜王&#xff08;juejin/csdn同名&#xff09; &#xff0c;一位前端勸退師 &#x1f47b; &#x1f440; 文章專欄&#xff1a; 高德AMap專欄 &#xff0c;記錄一下平時學習在博客寫作中記錄&#xff0c;總結出的一些開發技巧?。 感…

Sentinel[超詳細講解]-1

定義一系列 規則 &#x1f47a;&#xff0c;對資源進行 保護 &#x1f47a;&#xff0c; 如果違反的了規則&#xff0c;則拋出異常&#xff0c;看是否有fallback兜底處理&#xff0c;如果沒有則直接返回異常信息&#x1f60e; 1. 快速入門 1.1 引入 Sentinel 依賴 <depend…

02-Docker 使用

docker:快速構建、運行、管理應用的工具,可以幫助我們下載應用鏡像,創建并運行鏡像的容器,從而快速部署應用 1、部署mysql 先停掉虛擬機中的MySQL,確保你的虛擬機已經安裝Docker,且網絡開通的情況下,執行下面命令即可安裝MySQL(注意:若服務器上已經有mysql 占用了330…

@DeclareParents 注解實現接口功能增強:Spring中通過接口引入實現功能增強的完整示例

以下是Spring中通過接口引入實現功能增強的完整示例&#xff1a; // 1. 目標接口及實現類 package com.example;public interface Service {void doSomething(); }Component class ServiceImp implements Service {Overridepublic void doSomething() {System.out.println(&qu…

HTML中數字和字母不換行顯示

HTML中數字和字母不換行顯示的默認行為及如何通過CSS的word-wrap和word-break屬性進行調整。 在HTML中標簽中的數字和字母默認是不換行的&#xff0c;如果要將他們換行&#xff0c;在CSS中添加”word-wrap: break-word;” 即可解決 語法&#xff1a;word-wrap: normal|break-w…

Git團隊開發命令總結

簡易Git工作流 myname: 團隊成員個人分支dev: 團隊公共分支 個人獨立分支開發 同步最新的【dev公共分支】到本地。【重要】基于最新的【dev公共分支】&#xff0c;創建【個人功能開發分支】。在此基礎上開發。【個人功能開發分支】開發完成&#xff0c;推送到遠程庫。如果【…

Python人工智能大模型入門教程:從零構建高性能預測模型

引言&#xff1a;AI大模型時代的技術革命 在AlphaGo戰勝人類棋手的里程碑事件后&#xff0c;人工智能技術進入爆發式發展階段。本教程將帶您從零開始&#xff0c;使用Python構建一個工業級神經網絡模型。通過本教程&#xff0c;您不僅能掌握GPU加速訓練、混合精度計算等前沿技…

python-leetcode 61.N皇后

題目&#xff1a; 按照國際象棋的規則&#xff0c;皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。 n 皇后問題 研究的是如何將 n 個皇后放置在 nn 的棋盤上&#xff0c;并且使皇后彼此之間不能相互攻擊 給你一個整數 n &#xff0c;返回所有不同的 n 皇后問題 的解…

Mybatis_Plus中的常用注解

目錄 1、TableName TableId TableId的type屬性 TableField 1、TableName 經過以上的測試&#xff0c;在使用MyBatis-Plus實現基本的CRUD時&#xff0c;我們并沒有指定要操作的表&#xff0c;只是在 Mapper接口繼承BaseMapper時&#xff0c;設置了泛型User&#xff0c;而操…