MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)

news2024/9/17 9:04:30

1、MVC

MVC(Model-View-Controller) 是一种常用的架构模式,用于分离应用程序的逻辑、数据和展示。它通过三个核心组件(模型、视图和控制器)将应用程序的业务逻辑与用户界面隔离,促进代码的可维护性、可扩展性和模块化。在 MVC 模式中,各组件可以与多种设计模式结合使用,以增强灵活性和可维护性。以下是 MVC 各组件与常见设计模式的关系和作用:

1. Model(模型)

模型代表应用程序的核心数据和业务逻辑。它负责处理数据的存储、操作、验证和规则。

  • 设计模式:
    • 领域模型(Domain Model):模型中的业务逻辑可以使用领域模型设计模式进行封装,将业务逻辑与数据密切结合。例如,订单、用户、产品等实体类封装业务逻辑。
    • 观察者模式(Observer Pattern):当模型数据发生变化时,它可以通知视图更新。模型作为“被观察者”,视图作为“观察者”。观察者模式适合在模型改变时自动更新视图。
    • 代理模式(Proxy Pattern):模型中的数据可能通过代理模式进行远程调用或延迟加载,这样可以避免不必要的数据加载,增强性能。
    • 数据访问对象模式(DAO Pattern):与数据库交互时,可以通过 DAO 模式封装数据访问逻辑,将数据持久化操作与业务逻辑分离。

2. View(视图)

视图负责显示模型的数据,并将数据呈现给用户。它只关注如何将数据呈现,不负责业务逻辑。

  • 设计模式:
    • 组合模式(Composite Pattern):如果视图由多个子视图组合而成(如一个页面上有多个部件),组合模式可以将视图组合成一个树形结构,便于处理复杂的视图层次。
    • 装饰者模式(Decorator Pattern):通过装饰者模式,可以动态地为视图添加功能或行为,而不改变视图本身的结构。例如,添加滚动条、边框等。
    • 观察者模式(Observer Pattern):视图可以订阅模型的变化。当模型发生变化时,视图会自动更新。

3. Controller(控制器)

控制器负责响应用户输入并更新模型。它从视图接收用户的操作请求,并相应地更新模型或改变视图的状态。

  • 设计模式:
    • 命令模式(Command Pattern):控制器可以通过命令模式封装用户的操作请求,将其转化为命令对象。这样可以灵活处理用户操作,支持操作的撤销、重做等功能。
    • 策略模式(Strategy Pattern):控制器可以根据用户的输入或操作选择不同的处理策略。通过策略模式,控制器可以动态改变其行为,增强灵活性。
    • 前端控制器模式(Front Controller Pattern):Web 应用中,通常会有一个中央的控制器来处理所有的请求(如 Spring MVC 中的 DispatcherServlet),再根据请求选择具体的处理逻辑。前端控制器模式集中管理所有请求的路由和处理逻辑。

MVC 与各设计模式的结合关系:

  • 观察者模式 在 MVC 中非常重要,特别是在模型与视图之间。模型数据变化时自动通知视图更新,解耦了视图和模型之间的直接依赖。
  • 命令模式 可以用于控制器,将用户的操作封装为命令对象,使得操作可以记录、撤销或重做。这样特别适合复杂的交互场景。
  • 策略模式 可以用在控制器中,根据不同的用户输入或操作选择不同的处理方法。比如在输入不同格式的数据时,选择不同的验证逻辑。
  • 装饰者模式组合模式 可以用于视图层,尤其是在复杂的用户界面上,将界面元素进行组合、扩展和装饰,增强视图的灵活性。
  • 前端控制器模式 适用于大型 Web 应用中的请求处理,将所有的请求集中管理,并通过路由选择合适的控制器来处理请求。

总结

  • MVC 架构模式 本身就可以看作是一种宏观的设计模式,通过将模型、视图和控制器分离,解决了代码结构的分离与解耦问题。
  • 设计模式(如观察者、命令、策略、装饰者等)可以在 MVC 的具体实现中进一步增强组件的功能和灵活性。不同设计模式用于解决 MVC 各个组件之间的协作问题,以及增强代码的可扩展性和可维护性。

通过将 MVC 与各种设计模式结合,应用程序可以更加模块化、灵活,并且具备良好的扩展性。

2、MVVM

MVVM(Model-View-ViewModel) 是一种常用于构建用户界面(UI)应用程序的架构模式,它通过ModelViewViewModel 三个部分来分离业务逻辑、用户界面和数据处理,从而实现更清晰的职责划分、提高可维护性以及简化开发过程,特别适合需要数据绑定的场景。

MVVM 各部分职责

  1. Model(模型)

    • 负责应用程序的业务逻辑、数据访问和处理等。
    • 它独立于视图,处理应用程序的核心逻辑。
    • 例如数据库操作、API调用、数据验证等都属于Model的职责。
  2. View(视图)

    • 用户界面部分,用于展示数据并接收用户的输入。
    • View层与用户直接交互,负责UI的布局、元素的绘制和用户操作的响应。
    • 例如:按钮、文本框、列表等UI元素。
    • View不直接与Model交互,它通过ViewModel来获取和更新数据。
  3. ViewModel(视图模型)

    • 充当View和Model之间的桥梁,负责处理应用逻辑、状态管理、以及数据的双向绑定。
    • ViewModel可以从Model获取数据,处理业务逻辑,并将数据传递给View。
    • ViewModel通过观察机制通知View数据的变化,同时View也可以通过ViewModel改变Model的数据。

MVVM模式的工作流程

  • 双向绑定:MVVM最显著的特点是它支持View和ViewModel之间的双向数据绑定,这意味着当ViewModel中的数据发生变化时,View会自动更新,反之亦然。当用户在UI中做出修改时,这些更改会自动反映到ViewModel中。
  • 数据流
    1. 用户在View中执行某个操作(如点击按钮)。
    2. View通知ViewModel,ViewModel会处理该操作并可能更新Model中的数据。
    3. Model的数据变化时,ViewModel会感知到并通知View更新显示。

MVVM的优势

  1. 分离关注点:通过引入ViewModel,将视图逻辑和业务逻辑分离,减少了代码耦合,提升了代码的可维护性和复用性。
  2. 双向数据绑定:ViewModel和View之间实现了双向绑定,当Model中的数据更新时,UI会自动更新,这减少了手动同步UI状态的工作量。
  3. 更容易测试:由于ViewModel不依赖UI框架,单元测试可以集中在ViewModel中的业务逻辑上,而不涉及视图的复杂性。
  4. 简化复杂UI的管理:对于需要频繁更新UI的应用,MVVM通过ViewModel管理状态,简化了UI更新逻辑。

MVVM的劣势

  1. 复杂度增加:对于简单的应用,MVVM可能显得过于复杂,ViewModel的引入增加了初期的开发成本。
  2. 性能问题:大量的双向数据绑定可能在某些场景下带来性能开销,特别是当数据量大或更新频繁时。
  3. 学习曲线:对于没有使用过MVVM的开发者,理解ViewModel和数据绑定机制可能需要一定的时间和经验。

MVVM的典型应用场景

  • 桌面应用程序:特别是WPF(Windows Presentation Foundation)和UWP(Universal Windows Platform)等框架广泛使用MVVM架构。
  • 移动应用程序:例如Android开发中的Jetpack架构组件鼓励使用MVVM。
  • 复杂的单页应用(SPA):前端框架如Vue.js、Knockout.js等,也实现了类似于MVVM的双向数据绑定模式,适用于需要频繁动态更新的页面。

MVVM实现示例(Java Swing示例)

为了演示MVVM架构模式的工作原理,这里用Java的Swing GUI库创建一个简单的示例,展示如何通过MVVM模式实现一个简单的用户输入和展示。

1. Model:代表业务逻辑和数据
public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
2. ViewModel:负责将Model与View绑定
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class UserViewModel {
    private User user;
    private PropertyChangeSupport support;

    public UserViewModel(User user) {
        this.user = user;
        this.support = new PropertyChangeSupport(this);
    }

    public String getUserName() {
        return user.getName();
    }

    public void setUserName(String name) {
        String oldName = user.getName();
        user.setName(name);
        support.firePropertyChange("userName", oldName, name);
    }

    public int getUserAge() {
        return user.getAge();
    }

    public void setUserAge(int age) {
        int oldAge = user.getAge();
        user.setAge(age);
        support.firePropertyChange("userAge", oldAge, age);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        support.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        support.removePropertyChangeListener(listener);
    }
}
3. View:负责显示用户界面
import javax.swing.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

public class UserView extends JFrame implements PropertyChangeListener {
    private JTextField nameField;
    private JTextField ageField;
    private JLabel nameLabel;
    private JLabel ageLabel;
    private UserViewModel viewModel;

    public UserView(UserViewModel viewModel) {
        this.viewModel = viewModel;
        this.viewModel.addPropertyChangeListener(this);
        setupUI();
    }

    private void setupUI() {
        nameField = new JTextField(15);
        ageField = new JTextField(15);
        nameLabel = new JLabel("Name: ");
        ageLabel = new JLabel("Age: ");

        JButton updateButton = new JButton("Update");

        // 更新按钮的行为,使用ViewModel来处理
        updateButton.addActionListener(e -> {
            viewModel.setUserName(nameField.getText());
            viewModel.setUserAge(Integer.parseInt(ageField.getText()));
        });

        // 布局设置
        setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
        add(nameLabel);
        add(nameField);
        add(ageLabel);
        add(ageField);
        add(updateButton);

        setTitle("User Info");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if ("userName".equals(evt.getPropertyName())) {
            nameField.setText((String) evt.getNewValue());
        } else if ("userAge".equals(evt.getPropertyName())) {
            ageField.setText(evt.getNewValue().toString());
        }
    }

    public static void main(String[] args) {
        User user = new User("John Doe", 30);
        UserViewModel viewModel = new UserViewModel(user);
        UserView view = new UserView(viewModel);
        view.setVisible(true);
    }
}

总结

  • 在这个例子中,ModelUser负责保存用户的数据,ViewModelUserViewModel负责处理与Model的数据交互,ViewUserView负责展示用户界面并通过PropertyChangeListener绑定ViewModel的数据变化。
  • 通过MVVM架构,View与Model之间的依赖被削弱,ViewModel管理了数据绑定的逻辑,使代码更加模块化、易于维护。

3、对比

**MVVM(Model-View-ViewModel)MVC(Model-View-Controller)**都是流行的架构模式,用于构建可维护的用户界面应用程序。两者有相似的目标,都是为了分离关注点,但在实现和使用上各有优缺点。

MVC与MVVM对比

1. MVC模式
  • Model:表示数据和业务逻辑。它独立于用户界面,并且不直接与View交互。
  • View:负责显示Model的数据。View从Controller获取指令,更新界面。
  • Controller:充当Model和View之间的中介,处理用户输入并根据需要更新Model或View。
MVC的优点
  • 清晰的职责分离:Model、View、Controller各自负责独立的部分,降低代码耦合度。
  • 简单直观:适用于中小型应用,结构简单,易于理解。
  • 灵活性:Controller可以根据不同的输入调整Model或View的行为,拥有较高的灵活性。
  • 历史悠久:MVC模式已经被广泛使用,很多开发框架支持这种模式,社区和资源丰富。
MVC的缺点
  • Controller复杂度:随着系统规模增大,Controller的职责会变得复杂,需要处理大量逻辑和不同组件之间的交互,容易出现“肥大控制器”问题。
  • 双向绑定缺乏:MVC模式中的View和Model之间缺乏内置的双向绑定机制,View的状态更新需要手动处理,增加了管理的复杂度。
  • 测试困难:View和Controller之间的强耦合可能导致在进行单元测试时,测试的范围过大,不利于细粒度的测试。

2. MVVM模式
  • Model:和MVC中的Model类似,负责业务逻辑和数据处理。
  • View:负责用户界面和用户交互。
  • ViewModel:负责管理Model和View之间的数据和操作逻辑。ViewModel处理UI逻辑,且与View双向绑定,直接与View进行数据通信。
MVVM的优点
  • 双向数据绑定:MVVM模式支持双向数据绑定,ViewModel中的数据发生变化时,View会自动更新,反之亦然,减少了手动更新UI的工作量。
  • 弱化Controller的职责:MVVM将控制逻辑放到ViewModel中,避免Controller过度复杂化,简化了业务逻辑的实现。
  • 更容易测试:由于ViewModel不依赖于UI框架,逻辑集中在ViewModel中,且没有直接操作View,单元测试更容易实现。
  • 可复用性和扩展性:ViewModel可以根据不同的需求和上下文场景进行复用和扩展,便于维护。
  • 解耦性强:View和Model之间通过ViewModel解耦,降低了依赖性,尤其在复杂UI下,灵活性更高。
MVVM的缺点
  • 复杂度更高:对于简单应用来说,MVVM可能显得过于复杂。引入ViewModel层会增加初期开发成本和学习曲线。
  • 性能问题:在大量双向数据绑定的场景下,频繁的UI更新和数据变化可能导致性能问题,尤其在数据绑定的实现较为繁重时。
  • 学习成本:如果开发者不熟悉MVVM,尤其是双向绑定的机制,可能需要较长时间来适应该模式的使用。

MVC 与 MVVM 的优缺点对比

比较项MVCMVVM
复杂性相对较低,适合简单或中等复杂应用更高复杂度,适合大型复杂应用
职责分离清晰,但Controller易变得复杂职责更清晰,View和Model完全解耦
数据绑定没有内置数据绑定内置双向数据绑定,UI更新自动化
代码复用性Controller中的逻辑难以复用ViewModel中的逻辑易于复用
测试友好性Controller和View耦合较多,测试困难ViewModel易于测试
学习曲线相对简单,易于上手学习曲线较陡,双向绑定需要理解
性能表现UI更新手动控制,性能稳定频繁数据绑定可能影响性能

适用场景

  1. MVC 适用场景

    • 中小型应用:应用逻辑较为简单,界面与业务逻辑的交互不复杂。
    • 经典Web应用:很多传统的Web应用使用MVC架构,页面跳转和视图更新相对简单。
  2. MVVM 适用场景

    • 大型复杂应用:如桌面应用或移动应用,特别是需要频繁更新UI且有复杂数据展示和交互的系统。
    • 双向绑定需求强的场景:如需要大量动态数据展示的应用,如仪表盘或数据监控系统。

总结

  • MVC:更适合中小型应用,易于理解和实现。但随着复杂度增加,Controller部分可能变得笨重,代码复用性和可维护性较差。
  • MVVM:通过双向数据绑定,使得UI和逻辑层解耦,适合复杂场景,尤其是大量用户交互的应用。虽然复杂度较高,但更适合大型系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2117171.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++11 的继续学习

1.lambda 我们如果想要给一个自定义的元素排序,那么应该怎么排呢 先举个例子: struct Goods {string _name; // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price),…

等额本息等额本金

1、贷款计算器 2024年最新版房贷利率计算器_LPR利率计算器 (K JSON) 贷款计算器 2、等额本息 接下来,我们可以用Python编写一个函数来计算每月还款额: import pandas as pddef amortization_schedule(principal, annual_interest_rate, years):"…

MySQL事务执行过程

一、MySQL一个查询语句执行过程如下图🔽 MySQL客户端查询,经过查询缓存、解析器、查询优化器、查询执行引擎,通过API接口查询,经过存储引擎,获取数据返回给客户端。 二、事务执行过程如下图🔽 1、MySQL客户…

【生日视频制作】F900xr宝马摩托车提车交车仪式AE模板修改文字软件生成器教程特效素材【AE模板】

生日视频制作教程F900xr宝马摩托车提车交车仪式AE模板修改文字特效广告生成神器素材祝福玩法AE模板工程 AE模板套用改图文教程↓↓: 怎么如何做的【生日视频制作】F900xr宝马摩托车提车交车仪式AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤&a…

【变化检测】基于IFN建筑物(LEVIR-CD)变化检测实战及ONNX推理

主要内容如下: 1、LEVIR-CD数据集介绍及下载 2、运行环境安装 3、IFN模型训练与预测 4、Onnx运行及可视化 运行环境:Python3.8,torch1.12.0cu113 likyoo变化检测源码:https://github.com/likyoo/open-cd 使用情况:代…

00Mac 安装配置Python3虚拟环境(VirtualEnv、virtualenvwrapper扩展包)

文章目录 前言一、安装二、mac需要配置环境变量三、报错:workon: command not found 前言 本文主要记录,Mac 安装配置Python3虚拟环境(VirtualEnv、virtualenvwrapper扩展包),windows直接执行命令即可,mac…

Arch - 演进中的架构

文章目录 Pre原始分布式时代1. 背景与起源2. 分布式系统的初步探索3. 分布式计算环境(DCE)4. 技术挑战与困境5. 原始分布式时代的失败与教训6. 未来展望 单体时代优势缺陷单体架构与微服务架构的关系总结 SOA时代1. SOA架构及其背景1. 烟囱式架构&#x…

论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey

Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染:一项综述 文章目录 大规模语言模型的基准数据污染:一项综述摘要1 引言 摘要 大规模语言模型(LLMs&…

C#/.NET/.NET Core优质学习资料

前言 今天大姚给大家分享一些C#/.NET/.NET Core优质学习资料,希望可以帮助到有需要的小伙伴。 什么是 .NET? .NET 是一个免费的、跨平台的、开源开发人员平台,用于构建许多不同类型的应用程序。 使用 .NET,可以使用多种语言、编辑器和库来…

Java中Date类型上的注解

在日常开发中,涉及到日期时间类型Date和常用的注解DateTimeFormat和JsonFormat java.util.Date; org.springframework.format.annotation.DateTimeFormat; com.fasterxml.jackson.annotation.JsonFormat; 一 Date类型字段不使用注解 Data AllArgsConstructor N…

C语言程序设计——数组(一)

一、一维数组的定义和引用 数组:是一组具有相同数据类型的数据的有序集合。 1.1一维数组的定义 定义格式为: 类型说明符 数组名[常量表达式]; eg: int a[10]; 表示定义了一个整形数组,数组名为a,此数组有10个元素。 注:①数组名定名规则和变量名相同,遵循标识符…

【C++】STL学习——list模拟实现

目录 list介绍list结构介绍节点类的实现迭代器的实现构造函数运算符重载--运算符重载运算符重载!运算符重载*运算符重载->运算符重载 const迭代器的实现多参数模板迭代器list函数接口总览默认成员函数构造函数1构造函数2构造函数3 析构函数拷贝构造函数赋值重载函数 迭代器b…

八,SpringBoot Web 开发访问静态资源(附+详细源码剖析)

八,SpringBoot Web 开发访问静态资源(附详细源码剖析) 文章目录 八,SpringBoot Web 开发访问静态资源(附详细源码剖析)1. 基本介绍2. 快速入门2.1 准备工作 3. 改变静态资源访问前缀,定义为我们自己想要的4. 改变Spring Boot当中的默认的静态…

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext new ClassPathXmlApplicationContext("bean.xml"); } BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanFactory的功能相似,都是…

2024下学期学习总结加今日学习总结

Vue router Vue Router 是一个为 Vue.js 应用程序设计的官方路由管理器。它使你能够轻松地在 Vue 应用中实现页面导航,处理 URL 和视图的映射。 安装router 在运行框内输入 npm install vue-router4 //vue2专用 npm install vue-router3 //vue3专用 对router进…

uniapp数据缓存和发起网络请求

数据缓存 uni.onStorageSync同步的方式将数据存储到本地缓存 <template><button click"onStorageSync()">存储数据</button> </template><script setup>const onStorageSync () > {// 存储数据uni.setStorageSync(username, 张三)…

【验收交付体系文档】系统验收计划书,软件交付验收成套文档体系

软件系统验收计划书是确保新开发的软件系统符合预期要求并稳定运行的关键步骤。本计划书概述了验收过程的主要环节&#xff0c;包括系统功能的详细测试、性能评估、用户接受度测试以及文档完整性的核查。验收团队将依据项目需求规格说明书和合同要求&#xff0c;对系统进行全面…

axure判断

在auxre中我们也可以实现判断的功能&#xff0c;当目标等于什么内容时则执行下方的功能。 一、判断输入框中是否有值 画布添加一个输入框、一个文本标签删除其中内容&#xff0c;添加一个按钮&#xff0c;输入框命名为【文本显示】文本标签命名为【提示】 给按钮新增一个交互…

多个索引干扰导致索引失效如何解决

视频讲解&#xff1a;索引干扰导致索引失效如何解决_哔哩哔哩_bilibili 1 场景说明 表tb_order有订单状态order_status和创建时间create_time的索引。 现在业务的需求是&#xff0c;查询半年内&#xff0c;已支付订单状态的总数。SQL语句如下&#xff1a; SELECTCOUNT(1) FRO…

韦季李输入法_输入法和鼠标的深度融合

在数字化输入的新纪元&#xff0c;传统键盘输入方式正悄然进化。以往&#xff0c;面对实体键盘&#xff0c;我们常需目光游离于屏幕与键盘之间&#xff0c;以确认指尖下的精准位置。而屏幕键盘虽直观可见&#xff0c;却常因占据屏幕空间&#xff0c;迫使我们在操作与视野间做出…