我们将以“在线购物网站”作为例子贯穿全文,帮助您理解各种展示层设计模式的核心思想、优缺点及应用场景。
1. MVC 模式
1.1 核心思想
专业性描述
MVC 是 Model-View-Controller 的缩写,它是一种将业务逻辑、数据、界面显示分离的方法来组织代码的架构模式。
- Model(模型):代表应用程序的核心知识。它封装了应用程序的数据状态和业务逻辑。它不包含任何关于用户界面(UI)的信息,独立于控制器和视图。
- View(视图):代表模型的可视化表示。它负责将数据展示给用户,是用户看到并与之交互的界面。
- Controller(控制器):作为模型和视图之间的中介。它接收用户的输入(如鼠标点击、键盘输入),解析请求,调用模型进行业务处理,并选择相应的视图进行响应。
三者之间的交互流程如下:用户与 View 交互,View 将请求转发给 Controller,Controller 调用 Model 处理业务,Model 处理完毕后通知 View 更新数据,或者由 Controller 选择新的 View 展示结果。View 可以直接访问 Model 的数据进行展示,但不能直接修改 Model 中的数据,任何数据的修改(如更新库存、修改价格)都必须通过 Controller 来进行。
大白话类比
想象一个餐厅:
- Model(模型):厨房和食材,负责制作菜品(业务逻辑和数据)。
- View(视图):菜单和餐桌,展示给顾客看的东西。
- Controller(控制器):服务员,接收顾客的点单(输入),通知厨房制作菜品,然后把做好的菜端上桌。
顾客(用户)看菜单点菜,服务员记下并告诉厨房,厨房做好后服务员端上来。
“在线购物网站”示例
- Model:商品类 Product,包含商品 ID、名称、价格、库存等属性和相关的业务方法(如扣减库存)。
- View:商品列表页面 product_list,展示商品列表。
- Controller:ProductController,接收用户请求(如查看商品列表),调用 Product 模型获取数据,然后返回 product_list 视图。
用户访问商品列表页面时,Controller 从 Model 获取商品列表,然后交给 View 渲染成 HTML 返回给用户。
1.2 优点
- 低耦合:通过将视图层、控制层和模型层分离,使得各层之间的依赖性降低。修改视图层代码通常不需要改动模型层代码,反之亦然。这种解耦提高了系统的可维护性。
- 高复用性:一个模型可以对应多个视图。由于业务逻辑和数据封装在模型中,不同的视图可以共享同一个模型来展示数据,避免了业务逻辑的重复编写。
- 有利于分工协作:由于各层职责分明,在项目开发过程中,负责界面设计的工程师和负责业务逻辑的工程师可以并行工作,互不干扰。
- 可维护性与可扩展性强:分层架构使得系统结构清晰,当业务需求变更时,开发者可以快速定位到需要修改的层级,降低了系统维护的复杂度。
1.3 缺点
- 视图与模型耦合过紧:视图可以直接访问模型的数据结构来进行渲染。这就导致一旦模型的结构发生改变(例如数据库字段调整),视图层往往也需要随之修改,增加了维护成本。
- 控制器与视图耦合过紧:控制器完成业务逻辑处理后,必须明确指定由哪个 View 来展示结果。这意味着控制器并不完全独立于视图,它需要了解系统中有哪些具体的视图页面,以及它们的路径或名称。一旦视图的路径或名称发生变更,控制器的代码往往也需要随之修改。
- 不利于单元测试:由于视图与模型之间存在直接交互,对视图进行单元测试变得比较困难。测试视图时往往需要依赖真实的模型数据,导致测试不够独立和纯粹。
2. MVP 模式
2.1 核心思想
专业性描述
MVP 是 Model-View-Presenter 的缩写。它是 MVC 模式的一种演变,核心目的是为了彻底切断 View 和 Model 之间的直接联系。
- Model(模型):与 MVC 类似,依然负责数据的存储、检索和业务逻辑处理,完全不关心界面如何展示。
- View(视图):在 MVP 中,View 变得非常“被动”,被称为“被动视图”。它不再直接访问 Model,也不包含任何业务逻辑。它的职责仅仅是展示数据和接收用户的操作事件,并将事件全部转交给 Presenter。
- Presenter(展示器):这是 MVP 的核心。它充当了 View 和 Model 之间的“中间人”。它从 View 获取用户输入,调用 Model 处理业务,然后将处理结果通过接口的形式回调给 View 进行展示。
大白话类比
继续用餐厅比喻,但这次升级了:
- Model:厨房和食材,不变。
- View:智能点餐平板,只负责显示菜单和接收点触,不处理任何逻辑。
- Presenter:高级服务员,他拿着点餐平板,顾客在平板上点菜,平板把点菜信息给服务员,服务员去厨房下单,等菜做好了,服务员告诉平板更新显示“菜品已上齐”。
平板(View)只负责显示和接收点击,所有逻辑都在服务员(Presenter)那里。
“在线购物网站”示例
- Model:Product 模型,同 MVC。
- View:ProductListView 接口,定义了 showProducts(List<Product> products) 等方法,具体的实现可能是 ProductListActivity(Android)或 ProductListFragment(Web)。
- Presenter:ProductListPresenter,它持有 Product 模型和 ProductListView 接口的引用。当需要加载商品列表时,View 调用 Presenter 的 loadProducts() 方法,Presenter 调用 Model 获取数据,然后通过 View 接口的方法更新界面。
View 只负责展示,Presenter 负责所有的业务逻辑,Model 和 View 完全隔离。
2.2 优点
- View 与 Model 完全解耦:这是 MVP 最大的优势。View 不再持有 Model 的引用,两者通过 Presenter 隔离。这意味着 Model 的结构变化不会直接影响到 View 层的代码,极大地降低了耦合度。
- 视图层的“被动化”:View 只负责展示,不包含任何业务逻辑。这使得 View 层的代码非常简洁,UI 开发者可以专注于界面交互,而不用担心业务处理。
- 极高的可测试性:由于 View 只是一个接口,Presenter 不依赖于具体的 View 实现。我们可以很容易地通过模拟一个假的 View 对象来对 Presenter 进行单元测试,无需启动真实的界面或容器,测试速度和覆盖率都大幅提升。
3. MVVM 模式
3.1 核心思想
专业性描述
MVVM 是 Model-View-ViewModel 的缩写。它是一种基于数据驱动的架构模式,旨在进一步降低视图层与业务逻辑层的耦合度。
- Model(模型):与 MVC、MVP 中的职责一致,负责数据的存储、检索和业务逻辑,完全独立于界面。
- View(视图):负责 UI 界面的展示。与 MVP 不同的是,View 不再主动调用 Presenter 的方法,而是通过“数据绑定”的方式,将界面上的元素(如文本框、列表)与 ViewModel 中的数据进行关联。
- ViewModel(视图模型):这是 MVVM 的核心。它是 View 的抽象映射。它持有 View 所需的数据状态,并暴露出改变数据的方法。关键在于,ViewModel 不持有 View 的引用(这是与 MVP 最大的区别)。
核心机制:数据绑定。
View 和 ViewModel 之间通过双向或单向的数据绑定机制进行同步。当 ViewModel 中的数据发生变化时,绑定机制会自动更新 View;当 View 上的用户操作(如输入文字)改变数据时,绑定机制也会自动同步到 ViewModel 中。开发者不再需要手动编写“更新界面”的代码。
大白话类比
现在餐厅变成了全自动智能餐厅:
- Model:中央厨房和数据库。
- View:智能餐桌,上面有显示屏和感应器。
- ViewModel:餐桌的“大脑”,它存储了当前餐桌的订单状态、菜品信息等。
顾客在餐桌屏幕上点菜,屏幕(View)和餐桌大脑(ViewModel)是双向绑定的,点菜后大脑里的数据自动更新,同时大脑自动通知中央厨房(Model)做菜。菜做好了,大脑数据更新,屏幕自动显示菜品已上齐。全程没有服务员(Presenter)手动传递信息。
“在线购物网站”示例
- Model:Product 模型,同前。
- View:ProductList.vue(Vue 组件)或 ProductList.axml(小程序),其中使用
{{ product.name }} 这样的模板语法绑定数据。如果你正在使用或研究 Vue.js 这样的框架,MVVM 是其核心设计哲学。
- ViewModel:ProductListViewModel(在 Vue 中是组件的 data 和 methods),它包含一个 products 数组和一个 loadProducts 方法。当页面加载时,ViewModel 的 created 钩子调用 loadProducts 从 Model(通过 API)获取数据,并赋值给 products。因为 products 在 View 中通过 v-for 绑定,所以数据一变,列表自动更新。
开发者只需要关心 ViewModel 中的数据变化,UI 会自动更新,反之亦然。
3.2 优点
- 低耦合:View 和 ViewModel 之间没有直接的持有关系,它们通过数据绑定连接。这意味着 View 可以独立于 ViewModel 进行修改,只要绑定关系不变,ViewModel 的逻辑完全不需要调整。反之亦然。
- 可测试性:由于 ViewModel 不包含任何 View 的引用,它是一个纯粹的 Java/JavaScript 对象。这使得我们可以非常方便地针对 ViewModel 编写单元测试,无需模拟复杂的 UI 环境。
- 开发效率高:双向数据绑定机制节省了大量手动同步 UI 和数据的样板代码。开发者不再需要编写繁琐的 findViewById 或 document.getElementById 以及 setText 等更新界面的代码,极大地提高了开发效率。
- 团队协作友好:UI 设计师可以专注于编写 View 层的布局和样式,逻辑开发者可以专注于编写 ViewModel 的业务。由于数据绑存在,两者的工作边界非常清晰。
三种模式对比
| 模式 |
核心思想 |
通信方式 |
适用场景 |
| MVC |
分离显示、逻辑、数据,View 可直访 Model |
View → Controller → Model → View |
传统服务端渲染 Web 应用(如 JSP、Spring MVC) |
| MVP |
View 被动,通过 Presenter 与 Model 完全隔离 |
View → Presenter → Model → Presenter → View |
需要高可测试性的桌面应用或 Android 应用 |
| MVVM |
数据驱动,View 和 ViewModel 双向绑定 |
View ↔ ViewModel ←→ Model |
现代前端框架(Vue、Angular、WPF) |
4. 前后端分离
4.1 核心思想
专业性描述
前后端分离是目前 Web 开发的主流架构模式。它不仅仅是代码层面的分离,更是开发模式、部署方式和职责划分的全面变革。
核心定义:将原本混合在一起的项目拆分为两个独立的部分。
- 后端:专注于业务逻辑、数据处理、API 接口提供。它不再负责页面的构建和跳转,只输出数据(通常是 JSON 格式)。
- 前端:专注于界面交互、用户体验、页面渲染。它通过 HTTP 请求调用后端的 API 获取数据,然后在前端浏览器中完成页面的动态生成。
交互方式:采用 RESTful API 或 GraphQL 等方式进行异步通信。请求和响应的主体通常是 JSON 数据,而不是完整的 HTML 页面。
开发流程:前后端团队首先共同定义接口文档,然后并行开发。前端开发时可以模拟数据进行界面调试,待后端接口开发完成后进行联调。
大白话类比
像汽车制造:
- 后端:发动机制造厂,专门生产发动机(数据和服务)。
- 前端:汽车装配厂,专门制造车身、内饰、安装电子设备(界面和交互)。
装配厂(前端)根据标准接口(螺丝孔、电路接口)从发动机厂(后端)获取发动机,然后组装成完整的汽车。两家工厂独立运营,只要接口标准不变,可以各自升级改造。
“在线购物网站”示例
前端是一个独立的 SPA(单页应用),后端只是一个提供 JSON 的 API 服务器。
4.2 优点
- 职责分明,开发效率高:前端专注于界面交互,后端专注于业务逻辑和数据。这种分工让开发者能专注于自己擅长的领域,减少了上下文切换的成本。
- 前后端并行开发:在定义好 API 接口文档后,前端可以使用模拟数据进行开发,后端同时进行接口实现。两者互不阻塞,大大缩短了项目的开发周期。
- 多端适配性强:后端只提供数据接口,一套接口可以同时服务于 Web 端、移动端 App(iOS/Android)、小程序甚至第三方合作伙伴。极大地复用了后端逻辑,避免了重复开发。
- 维护成本低:前端和后端代码库独立。当需要修改界面时,只需重新部署前端代码,无需重启后端服务器;反之亦然。这降低了系统维护的风险。
4.3 缺点
- 首屏加载速度较慢:前端需要先下载大量的 JavaScript 文件,然后执行 JS 去请求后端数据,最后渲染页面。相比服务端直接返回 HTML,这个过程在弱网环境或低配置设备上会导致“白屏”时间较长。
- SEO(搜索引擎优化)困难:搜索引擎的爬虫程序(如 Google、百度的蜘蛛)在抓取页面时,往往难以执行复杂的 JavaScript 代码。如果页面内容全靠 JS 渲染,爬虫看到的可能是一片空白,导致网站在搜索结果中排名靠后。
- 系统复杂度增加:需要维护两个独立的项目,涉及到跨域问题、接口版本管理、前后端联调成本等,对团队的技术栈要求更高。
5. 服务端渲染
专业性描述
当浏览器请求页面时,服务器端执行 JavaScript 代码(Vue/React 组件),获取所需的数据,并将其填充到模板中,生成完整的 HTML 字符串,然后直接返回给浏览器。浏览器接收到的是一张已经包含所有内容的网页,而不是空白的壳子。
大白话类比
传统印刷 vs 数字印刷:
- 客户端渲染(CSR):就像寄给客户一本空白笔记本和印刷机,客户自己收到后现场印刷内容(慢,依赖客户设备)。
- 服务端渲染(SSR):印刷厂直接印好整本书寄给客户,客户收到就能看(快,不依赖客户设备)。
“在线购物网站”示例
- 问题:采用前后端分离后,商品列表页首屏加载慢,且搜索引擎收录不好。
- SSR 解决方案:使用 Nuxt.js(Vue)或 Next.js(React)进行服务端渲染。
- 用户请求商品列表页。
- 请求到达 Node.js 服务器(运行 Nuxt.js)。
- Nuxt.js 调用后端 API 获取商品数据。
- Nuxt.js 将数据填充到 Vue 组件中,在服务器端渲染出完整的 HTML。
- 将 HTML 返回给浏览器,浏览器立即显示完整页面。
- 同时,浏览器加载的 JavaScript 代码会“接管”页面,使其变为可交互的 SPA。
优点:首屏快、SEO 友好,同时保留了 SPA 的交互体验。
6. 响应式 Web 设计
专业性描述
响应式 Web 是一种网页设计的技术方法,旨在让一个网站能够自动适应不同设备的屏幕尺寸、分辨率和方向(横屏或竖屏),从而在所有设备上(从桌面电脑显示器到平板、手机)都能提供最佳的浏览体验——包括易于阅读的文字、无需缩放或横向滚动的导航和图片。
核心思想:一套代码,到处适应。它不是为每种设备分别开发一个独立的网站(例如 m.example.com),而是通过技术手段,让同一个 HTML 页面能够根据访问设备的特征,动态地调整其布局和样式。
关键技术:
- 流式布局:使用相对单位(如百分比 %、视口单位 vw/vh)而不是绝对单位(如像素 px)来定义元素的宽度。这样,元素的宽度会基于父容器或视口宽度进行弹性缩放。
- 弹性图片/媒体:通过 CSS 设置图片和视频的最大宽度为 100%,确保它们永远不会超过其容器的宽度,从而在不同尺寸的屏幕上都能完整显示,避免溢出。
- CSS 媒体查询:这是响应式设计的核心。它允许开发者编写针对不同设备特性(主要是屏幕宽度)的 CSS 样式规则。例如,可以定义:当屏幕宽度小于 600 像素时(即手机竖屏),将侧边栏隐藏,并将导航菜单改为汉堡菜单;当屏幕宽度在 601 到 1024 像素之间时(即平板),将侧边栏移到页面底部;当屏幕宽度大于 1024 像素时(即桌面),则显示完整的布局。
大白话类比
像一件“弹性布料”做的衣服,能适应不同身材的人:
- 身材瘦小(手机):衣服自动收缩,裁剪合身。
- 身材中等(平板):衣服适当调整。
- 身材高大(桌面):衣服充分展开,展现全部设计。
同一件衣服,不用换,自动适应。
“在线购物网站”示例
- PC端(> 1024px):显示完整导航栏、侧边栏筛选、商品网格布局(一行 4 个商品)。
- 平板端(601px - 1024px):导航栏简化,侧边栏折叠成可展开的抽屉,商品网格一行 2 个。
- 手机端(< 600px):导航栏变成汉堡菜单,侧边栏隐藏,商品列表变成单列垂直排列。
通过媒体查询,为不同宽度的屏幕编写不同的 CSS 规则,实现一套代码适配所有设备。
7. 跨平台开发
7.1 Web App
专业性描述
通过移动设备的浏览器访问的 Web 应用,本质上是针对移动端优化的响应式网站。通常使用 HTML5、CSS3、JavaScript 开发。
“在线购物网站”示例:用户通过手机浏览器访问 m.shop.com,获得针对手机优化的 Web 界面。优点:开发维护一套代码,无需安装。缺点:性能、体验和功能访问权限(如摄像头、推送)不及原生 App。
7.2 Flutter
专业性描述
Google 推出的 UI 工具包,使用 Dart 语言,通过自绘引擎直接渲染 UI,实现高性能的跨平台应用(iOS、Android、Web、桌面)。
“在线购物网站”示例:用 Flutter 开发“在线购物” App,一套 Dart 代码可编译成 iOS 和 Android 应用,UI 性能接近原生,且具有高度一致性。
7.3 React Native
专业性描述
使用 JavaScript 和 React 编写,通过桥接调用原生组件,在保留原生体验的同时实现跨平台开发。
“在线购物网站”示例:用 React Native 开发 App,大部分业务逻辑用 JavaScript 编写,UI 组件映射为原生控件。适合有 Web 前端 React 经验的团队。
7.4 uni-app
专业性描述
基于 Vue.js 的跨端框架,一套代码可发布到 iOS、Android、Web、小程序(微信/支付宝/百度等)平台。
“在线购物网站”示例:用 uni-app 开发,可以同时生成微信小程序、App 和 H5 版本,特别适合需要快速覆盖小程序和 App 的场景。
7.5 Taro
专业性描述
京东推出的多端统一开发框架,支持用 React 语法编写,可编译到微信/支付宝/百度小程序、H5、React Native 等。
“在线购物网站”示例:有 React 技术栈的团队,使用 Taro 开发小程序和 H5,代码复用率高。
总结
展示层设计模式从传统的 MVC 到解耦更彻底的 MVP,再到数据驱动的 MVVM,体现了关注点分离和降低耦合度的持续演进。前后端分离架构适应了现代 Web 开发多端的需求,而服务端渲染和响应式设计则分别解决了性能体验和多设备适配的挑战。最后,跨平台开发技术让我们能用更少的成本覆盖更多终端。实际项目中,需要根据团队技术栈、项目规模和具体需求(如性能、SEO、开发效率)来选择合适的模式和技术组合。
希望这篇关于展示层设计的梳理能帮助你更好地进行架构决策。如果你在技术选型或实践中有更多想法,欢迎在 云栈社区 与我们交流。