系统架构:MVVM

news2024/12/1 14:23:54

引言

MVVM 全称 Model-View-ViewModel,是在 MVP(Model-View-Presenter)架构模式基础上的进一步演进与优化。MVVM 与 MVP 的基本架构相似,但 MVVM 独特地引入了数据双向绑定机制。这一创新机制有效解决了 MVP 模式中 Model 与 View 之间存在的耦合问题,极大地简化了两者间的映射关系以及繁琐的 DOM 操作流程。MVVM 架构模式致力于助力开发者更高效地分离用户界面(UI)与复杂的业务逻辑,进而显著提升代码的可维护性与可扩展性。

MVVM架构范式最初由微软架构师Ken Cooper和Ted Peters提出,并在Windows Presentation Foundation(WPF)平台上成功实施。由另外一位微软架构师 John Gossman在其博客《Introduction to Model/View/ViewModel pattern for building WPF apps》中发布。

MVVM的组件

MVVM 主要由 Model、View、ViewModel 和 DataBinding 四个核心组件构成,其架构关系图示如下:
在这里插入图片描述

View

View组件即用户界面(User Interface),在MVVM架构中,View只包含一层很薄的展示逻辑。View通过数据绑定(DataBinding)与ViewModel进行交互。当View与ViewModel完成数据绑定后,View中的任何变化都会自动反馈到ViewModel中,而View则无法直接感知Model的存在。这种设计使得View更加专注于展示,而不需要处理复杂的业务逻辑。

Model

Model组件与MVP架构中的Model类似,负责数据的存储和管理。Model层提供数据更新接口供ViewModel调用,以实现数据的更新。当Model中的数据发生变化时,会通过通知机制(如Notify)告知ViewModel,以便ViewModel进行相应的处理。

ViewModel

ViewModel组件位于View和Model之间,负责将Model的数据转换成View可以感知的形式。ViewModel通过数据绑定(DataBinding)将数据与View进行绑定,使得数据的变化能够自动更新到View上,从而实现数据的双向绑定。此外,ViewModel还通常包含用户的交互逻辑,如处理按钮点击等事件。

DataBinding

数据绑定(DataBinding)是MVVM架构中实现View和ViewModel之间数据双向流动更新的核心机制。在MVC或MVP架构中,View的更新和响应需要开发者编写大量复杂且冗余的代码。而在MVVM架构中,由于数据绑定的存在,开发者无需编写这部分复杂的代码,可以将更多的精力投入到核心业务功能的开发上。

MVVM实现

MVVM 涵盖 View、ViewModel、Model、DataBinding 四个核心模块。一般而言,View 对应相应页面布局的 xml 文件;ViewModel 对应业务逻辑的实现;DataBinding 负责建立页面布局文件与 ViewModel 业务实现之间的绑定关系。在 Android 开发环境中,由于存在原生 DataBinding 库,我们往往难以一窥 DataBinding 实现的全貌。鉴于 C++ 本身缺乏类似 Android 的原生 DataBinding 库,此处我们依据 DataBinding 的观察者实现原理,编写一个 C++ 版本的用户登录 MVVM 示例,以此助力大家深入透彻地理解 MVVM 实现的精髓。

Observer接口

#include <vector>
#include <string>

class Observer
{
public:
    virtual void onChanged(const std::string& fieldName) = 0;
    virtual ~Observer() = default;
};

ObservableField 类

ObservableField 类是数据绑定的核心要素,承担着存储数据以及在数据变更时通知所有观察者的关键职责。

template <typename T>
class ObservableField
{
public:
    explicit ObservableField(const std::string& fieldName, T value)
    : m_fieldName(fieldName)
    , m_value(std::move(value))
    {
    }

    void set(T value)
    {
        if (m_value != value)
        {
            m_value = std::move(value);
            notifyObservers();
        }
    }

    const T& get() const
    {
        return m_value;
    }

    void addObserver(Observer* observer)
    {
        m_observers.push_back(observer);
    }

private:
    void notifyObservers()
    {
        for (auto observer : m_observers)
        {
            if (observer)
            {
                observer->onChanged(m_fieldName);
            }
        }
    }

    std::string m_fieldName;
    T m_value;
    std::vector<Observer*> m_observers;
};

Model 类

UserModel 类用于验证用户名和密码。

#include <string>

class UserModel
{
public:
    UserModel(std::string correctUsername, std::string correctPassword)
    : m_correctUsername(std::move(correctUsername))
    , m_correctPassword(std::move(correctPassword))
    {
    }

    bool validateLogin(const std::string& username, const std::string& password) const
    {
        return username == m_correctUsername && password == m_correctPassword;
    }

private:
    std::string m_correctUsername;
    std::string m_correctPassword;
};

ViewModel 类

ViewModel 是 MVVM 模式的核心枢纽,它有效分离了业务逻辑与视图。ViewModel 负责从 Model 获取数据,处理用户输入,并通过 ObservableField 通知视图更新。

class View; // 前向声明

class ViewModel : public Observer
{
public:
    ViewModel(UserModel* model)
    : m_model(model)
    , m_view(nullptr)
    , m_usernameField("username", "")
    , m_passwordField("password", "")
    {
        m_usernameField.addObserver(this);
        m_passwordField.addObserver(this);
    }

    void setView(View* view)
    {
        m_view = view;
    }

    void setUsername(const std::string& username)
    {
        m_usernameField.set(username);
    }

    void setPassword(const std::string& password)
    {
        m_passwordField.set(password);
    }

    void login()
    {
        if (m_model->validateLogin(m_usernameField.get(), m_passwordField.get()))
        {
            std::cout << "Login successful!" << std::endl;
        }
        else
        {
            std::cout << "Login failed! Incorrect username or password." << std::endl;
        }
    }

    void onChanged(const std::string& fieldName) override
	{
	    if (m_view)
	    {
	        m_view->updateField(fieldName);
	    }
	}

    const std::string& getUsername() const
    {
        return m_usernameField.get();
    }

    const std::string& getPassword() const
    {
        return m_passwordField.get();
    }

private:
    UserModel* m_model;
    View* m_view;

    ObservableField<std::string> m_usernameField;
    ObservableField<std::string> m_passwordField;
};

View 类

View 类负责与用户进行交互,接收用户输入并传递给 ViewModel,同时负责更新 UI 界面。

class View
{
public:
    explicit View(ViewModel* viewModel)
    : m_viewModel(viewModel)
    {
    }

    void simulateUserInput()
    {
        std::string username, password;

        std::cout << "Enter username: ";
        std::getline(std::cin, username);
        m_viewModel->setUsername(username);

        std::cout << "Enter password: ";
        std::getline(std::cin, password);
        m_viewModel->setPassword(password);

        m_viewModel->login();
    }

    void updateField(const std::string& fieldName)
    {
        if (fieldName == "username")
        {
            std::cout << "Updated Username: " << m_viewModel->getUsername() << std::endl;
        }
        else if (fieldName == "password")
        {
            std::cout << "Updated Password: " << m_viewModel->getPassword() << std::endl;
        }
    }

private:
    ViewModel* m_viewModel;
};

主程序 (Main)

在 main 函数中,我们创建 UserModel、ViewModel 和 View 实例,并模拟用户输入来验证登录。


int main() 
{
    UserModel userModel("user", "password");
    ViewModel viewModel(&userModel);
    View view(&viewModel);

    viewModel.setView(&view);

    view.simulateUserInput();
}

如果用户输入正确的用户名和密码,程序输出如下:

Enter username: user
Updated Username: user
Enter password: password
Updated Password: password
Login successful!

如果用户输入错误的用户名或密码,程序输出如下:

Enter username: a
Updated Username: a
Enter password: b
Updated Password: b
Login failed! Incorrect username or password.

总结

MVVM 架构模式作为一种先进的软件设计模式,通过引入数据双向绑定机制,成功地在 Model、View 和 ViewModel 之间构建起高效的协同工作体系。在该架构中,View 专注于展示,Model 专注于数据管理,ViewModel 则作为桥梁,负责数据转换与交互逻辑处理,DataBinding 确保了数据的自动双向流动。这种职责分离的设计极大地提高了代码的可维护性与可扩展性,降低了各组件之间的耦合度。本文通过 C++ 实现的用户登录示例,深入剖析了 MVVM 的各个组件及其实现原理,展示了 MVVM 在实际应用中的工作流程。无论是对于前端开发还是后端开发,理解和掌握 MVVM 架构模式都有助于提升软件开发的质量与效率,为构建复杂而稳定的应用程序奠定坚实的基础。

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

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

相关文章

家校通小程序实战教程04教师管理

目录 1 创建数据源2 搭建管理后台3 搭建查询条件4 功能测试总结 我们上一篇介绍了如何将学生加入班级&#xff0c;学生加入之后就需要教师加入了。教师分为任课老师和班主任&#xff0c;班主任相当于一个班级的管理员&#xff0c;日常可以发布各种任务&#xff0c;发布接龙&…

cesium 3Dtiles变量

原本有一个变亮的属性luminanceAtZenith&#xff0c;但是新版本的cesium没有这个属性了。于是 let lightColor 3.0result._customShader new this.ffCesium.Cesium.CustomShader({fragmentShaderText:void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial mate…

SpringBoot小知识(3):热部署知识

一、热部署 热部署是一个非常消耗内存的机制&#xff0c;在实际大型项目开发中几乎用不到&#xff0c;只有小型项目或者分模块或者不停机更新的时候才会用到&#xff0c;仁者见仁智者见智。 1.1 什么是热部署&#xff1f; 热部署是指在不停止应用程序或服务器的情况下&#xf…

vscode切换anaconda虚拟环境解释器不成功

问题&#xff1a; 切换解释器之后运行代码还是使用的原来的解释器 可以看到&#xff0c;我已经切换了“nlp”解释器&#xff0c;我的nltk包只在“nlp”环境下安装了&#xff0c;但是运行代码依然是"torch"解释器&#xff0c;所以找不到“nltk”包。 在网上找了各种…

widows下永久修改python的pip 配置文件

通过cmd永久修改pip 镜像源&#xff1a; 在cmd中输入&#xff1a; pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple会在"C:\Users\Administrator\AppData\Roaming"目录下创建一个pip\pip.ini文件&#xff1a; 使用记事本打开pip.ini文件…

openssl使用哈希算法生成随机密钥

文章目录 一、openssl中随机数函数**OpenSSL 随机数函数概览**1. **核心随机数函数** **常用函数详解**1. RAND_bytes2. RAND_priv_bytes3. RAND_seed 和 RAND_add4. RAND_status **随机数生成器的熵池****常见用例****注意事项** 二、使用哈希算法生成随机的密钥 一、openssl中…

【Python网络爬虫笔记】6- 网络爬虫中的Requests库

一、概述 Requests 是一个用 Python 语言编写的、简洁且功能强大的 HTTP 库。它允许开发者方便地发送各种 HTTP 请求&#xff0c;如 GET、POST、PUT、DELETE 等&#xff0c;并且可以轻松地处理请求的响应。这个库在 Python 生态系统中被广泛使用&#xff0c;无论是简单的网页数…

pytest+allure生成报告显示loading和404

pytestallure执行测试脚本后&#xff0c;通常会在电脑的磁盘上建立一个临时文件夹&#xff0c;里面存放allure测试报告&#xff0c;但是这个测试报告index.html文件单独去打开&#xff0c;却显示loading和404, 这个时候就要用一些办法来解决这个报告显示的问题了。 用命令产生…

NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比

NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测&#xff0c;含优化前后对比 目录 NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测&#xff0c;含优化前后对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介…

【S500无人机】--地面端下载

之前国庆的时候导师批了无人机&#xff0c;我们几个也一起研究了几次&#xff0c;基本把无人机组装方面弄的差不多了&#xff0c;还差个相机搭载&#xff0c;今天我们讲无人机的调试 硬件配置如下 首先是地面端下载&#xff0c;大家可以选择下载&#xff1a; Mission Planne地…

CSAPP Cache Lab(缓存模拟器)

前言 理解高速缓存对 C 程序性能的影响&#xff0c;通过两部分实验达成&#xff1a;编写高速缓存模拟器&#xff1b;优化矩阵转置函数以减少高速缓存未命中次数。Part A一开始根本不知道要做什么&#xff0c;慢慢看官方文档&#xff0c;以及一些博客&#xff0c;和B站视频&…

Linux内核4.14版本——ccf时钟子系统(3)——ccf一些核心结构体

目录 1. struct clk_hw 2. struct clk_ops 3. struct clk_core 4. struct clk_notifier 5. struct clk 6. struct clk_gate 7. struct clk_divider 8. struct clk_mux 9. struct clk_fixed_factor 10. struct clk_fractional_divider 11. struct clk_multiplier 12…

点云处理中obb算法原理和法向量求解方法

主要数学原理PCA PCA&#xff08;Principal Component Analysis&#xff0c;主成分分析&#xff09;是数据分析中的一种重要技术&#xff0c;通过它可以将高维数据投影到低维空间&#xff0c;找到数据的主要结构。在点云分析中&#xff0c;PCA 可以帮助我们提取点云数据中的主…

shell编程7,bash解释器的 for循环+while循环

声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&#…

【人工智能】Python常用库-TensorFlow常用方法教程

TensorFlow 是一个广泛应用的开源深度学习框架&#xff0c;支持多种机器学习任务&#xff0c;如深度学习、神经网络、强化学习等。以下是 TensorFlow 的详细教程&#xff0c;涵盖基础使用方法和示例代码。 1. 安装与导入 安装 TensorFlow&#xff1a; pip install tensorflow…

wxFormBuilder:可视化设计、学习wxWidgets自带UI控件的好工具

wxFormBuilder很快就能拼出一个界面&#xff0c;而且可以直接出对应的代码&#xff0c;拷贝到项目里小改一下就能用。

Vim操作

1. Vim的模式 2.正常模式->编辑模式 在上⽅插⼊⼀⾏&#xff1a; O在下⽅插⼊⼀⾏&#xff1a; o (open)在当前光标前插⼊&#xff1a; i在⾏⾸插⼊&#xff1a; I在当前光标后插⼊&#xff1a; a在⾏尾插⼊&#xff1a; A 3.常见命令行 1、拷贝当前行 yy ,拷贝当前行向下…

阿里云服务器(centos7.6)部署前后端分离项目(MAC环境)

Jdk17安装部署 下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/ 选择自己需要的jdk版本进行下载。 通过mac终端scp命令上传下载好的jdk17到服务器的/usr/local目录下 scp -r Downloads/jdk-17.0.13_linux-x64_bin.tar.gz 用户名服务器ip地址:/us…

「Mac畅玩鸿蒙与硬件33」UI互动应用篇10 - 数字猜谜游戏

本篇将带你实现一个简单的数字猜谜游戏。用户输入一个数字&#xff0c;应用会判断是否接近目标数字&#xff0c;并提供提示“高一点”或“低一点”&#xff0c;直到用户猜中目标数字。这个小游戏结合状态管理和用户交互&#xff0c;是一个入门级的互动应用示例。 关键词 UI互…

Python系列 - MQTT协议

Python系列 - MQTT协议 资源连接 MQTT的介绍和应用场景的示例说明 一、什么是MQTT 百度关于MQTT的介绍如下&#xff1a; MQTT(消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布订阅范式的消息协议。它工作在 TCP/IP协议之上&#xff0c;是为硬件性能低下的远程设…