系统架构:MVVM

引言

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 架构模式都有助于提升软件开发的质量与效率,为构建复杂而稳定的应用程序奠定坚实的基础。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络协议(TCP/IP模型)

目录 网络初识 网络协议 协议分层 协议拆分 分层 协议分层的优势 1.封装效果 2.解耦合 TCP/IP五层模型 协议之间配合工作&#xff08;详解&#xff09; 网络初识 网络核心概念&#xff1a; 局域网&#xff1a;若干电脑连接在一起&#xff0c;通过路由器进行组网。 …

网络安全之IP伪造

眼下非常多站点的涉及存在一些安全漏洞&#xff0c;黑客easy使用ip伪造、session劫持、xss攻击、session注入等手段危害站点安全。在纪录片《互联网之子》&#xff08;建议搞IT的都要看下&#xff09;中。亚伦斯沃茨&#xff08;真实人物&#xff0c;神一般的存在&#xff09;涉…

软件工程之静态建模

静态模型&#xff1a;有助于设计包、类名、属性和方法特征标记&#xff08;但不是方法体&#xff09;的定义&#xff0c;例如UML类图。 用例的关系&#xff1a; 扩展关系&#xff1a; 扩展关系允许一个用例&#xff08;可选&#xff09;扩展另一个用例&#xff08;基用例&…

JS听到了爆燃的回响

Window对象 BOM&#xff08;浏览器对象模型&#xff09; BOM是浏览器对象模型 Window对象是一个全局对象&#xff0c;也可以说是JS中的顶级对象 像是document、alert()、console.log()都是window的属性 所有通过var定义在全局作用域的变量、函数都会变成window对象的属性和…

【Linux】死锁、读写锁、自旋锁

文章目录 1. 死锁1.1 概念1.2 死锁形成的四个必要条件1.3 避免死锁 2. 读者写者问题与读写锁2.1 读者写者问题2.2 读写锁的使用2.3 读写策略 3. 自旋锁3.1 概念3.2 原理3.3 自旋锁的使用3.4 优点与缺点 1. 死锁 1.1 概念 死锁是指在⼀组进程中的各个进程均占有不会释放的资源…

单片机学习笔记 15. 串口通信(理论)

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…

MyBatis异常体系中ErrorContext和ExceptionFactory原理分析

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 exceptions包分包设计ExceptionFactory类介绍为什么使用工厂不是直接new呢&#xff1f;【统一的异常处理机制】【异常的封装与转化】【…

【Canvas与雷达】点鼠标可暂停金边蓝屏雷达显示屏

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>点鼠标可暂停金边蓝屏雷达显示屏 Draft1</title><style typ…

Spark Optimization —— Reducing Shuffle

Spark Optimization : Reducing Shuffle “Shuffling is the only thing which Nature cannot undo.” — Arthur Eddington Shuffle Shuffle Shuffle I used to see people playing cards and using the word “Shuffle” even before I knew how to play it. Shuffling in c…

数据结构 (22)哈夫曼树及其应用

前言 哈夫曼树&#xff08;Huffman Tree&#xff09;&#xff0c;又称最优二叉树或最优树&#xff0c;是一种特殊的二叉树结构&#xff0c;其带权路径长度&#xff08;WPL&#xff09;最短。 一、哈夫曼树的基本概念 定义&#xff1a;给定N个权值作为N个叶子结点&#xff0c;构…

Android Studio安装TalkX AI编程助手

文章目录 TalkX简介编程场景 TalkX安装TalkX编程使用ai编程助手相关文章 TalkX简介 TalkX是一款将OpenAI的GPT 3.5/4模型集成到IDE的AI编程插件。它免费提供特定场景的AI编程指导&#xff0c;帮助开发人员提高工作效率约38%&#xff0c;甚至在解决编程问题的效率上提升超过2倍…

泷羽sec-shell脚本(全) 学习笔记

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

开发者如何使用GCC提升开发效率IMG操作

看此篇前请先阅读https://blog.csdn.net/qq_20330595/article/details/144134160?spm1001.2014.3001.5502 stb_image库配置 https://github.com/nothings/stb 代码 #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #define STB_IMAGE_WRITE_IMPLEM…

vue3【实战】面包屑【组件封装】Breadcrumb (根据菜单自动生成,实时响应路由变化,添加顺滑的过渡动画)

效果预览 技术方案 vue3 ( vite | TS | vueUse | AutoImport ) Element Plus UnoCSS 技术要点 根据当前路由查询所有父级路由 /*** 从树状列表中获取指定节点的所有父节点** param treeList 树状列表&#xff0c;包含多个节点* param value 目标节点的路径值* param parents…

pdf也算是矢量图——pdf大小调整--福昕pdf

有时候需要把pdf作为矢量图放到latex论文中&#xff0c;有时候需要裁剪掉空白的部分&#xff0c;就需要用福昕pdf进行编辑&#xff0c; 参考文章&#xff1a;福昕高级PDF编辑器裁切工具怎么用&#xff1f;裁切工具使用方法介绍_福昕PDF软件工具集 (foxitsoftware.cn)

【k8s】kubelet 的相关证书

在 Kubernetes 集群中&#xff0c;kubelet 使用的证书通常存放在节点上的特定目录。这些证书用于 kubelet 与 API 服务器之间的安全通信。具体的位置可能会根据你的 Kubernetes 安装方式和配置有所不同&#xff0c;下图是我自己环境【通过 kubeadm 安装的集群】中的kubelet的证…

Java项目Docker部署

docker将应用程序与该程序的依赖打包在一个文件里。运行这个文件就会生成一个虚拟容器&#xff0c;就不用担心环境问题&#xff0c;还可以进行版本管理、复制修改等。 docker安装 由于在CentOS下安装docker最常用&#xff0c;所以以Linux环境安装为主 1.安装工具包 缺少依赖…

【数据结构与算法】排序算法(上)——插入排序与选择排序

文章目录 一、常见的排序算法二、插入排序2.1、直接插入排序2.2、希尔排序( 缩小增量排序 ) 三、选择排序3.1、直接选择排序3.2、堆排序3.2.1、堆排序的代码实现 一、常见的排序算法 常见排序算法中有四大排序算法&#xff0c;第一是插入排序&#xff0c;二是选择排序&#xff…

Flink四大基石之Time (时间语义) 的使用详解

目录 一、引言 二、Time 的分类及 EventTime 的重要性 Time 分类详述 EventTime 重要性凸显 三、Watermark 机制详解 核心原理 Watermark能解决什么问题,如何解决的? Watermark图解原理 举例 总结 多并行度的水印触发 Watermark代码演示 需求 代码演示&#xff…

虚拟机docker记录

最近看了一个up的这个视频&#xff0c;感觉docker真的挺不错的&#xff0c;遂也想来搞一下&#xff1a; https://www.bilibili.com/video/BV1QC4y1A7Xi/?spm_id_from333.337.search-card.all.click&vd_sourcef5fd730321bc0e9ca497d98869046942 这里我用的是vmware安装ubu…