C# 面试问题高级:050 - 什么是MVVM(Model-View-ViewModel)设计模式 ?

在现代软件开发中,用户界面(UI)的设计和实现变得越来越复杂。为了更好地分离关注点、提高代码的可维护性和测试性,许多设计模式应运而生。MVVM(Model-View-ViewModel)是其中一种非常流行的设计模式,特别适用于使用数据绑定技术的应用程序。

什么是 MVVM?

定义

MVVM(Model-View-ViewModel)是一种架构设计模式,用于简化用户界面(UI)的开发。它将应用程序分为三个主要部分:

  1. Model:负责处理业务逻辑和数据存储。
  2. View:负责显示数据并与用户交互。
  3. ViewModel:作为中介,负责将 Model 中的数据转换为 View 可以使用的格式,并处理来自 View 的用户输入。

基本概念

  1. Model:包含应用程序的核心业务逻辑和数据存储。它可以是数据库访问层、Web API 客户端或其他数据源。
  2. View:负责呈现数据并处理用户输入。它是用户与应用程序交互的主要界面。
  3. ViewModel:作为中介,负责将 Model 中的数据转换为 View 可以使用的格式,并处理来自 View 的用户输入。它通常包含命令(Command)和属性(Property),以便与 View 进行双向数据绑定。

示例场景

假设我们需要开发一个简单的待办事项应用程序,允许用户添加、删除和查看待办事项。我们可以使用 MVVM 模式来实现这个应用程序,从而更好地分离关注点,提高代码的可维护性和测试性。

MVVM 的实现

下面我们将通过一个具体的例子来展示如何在 C# 中实现 MVVM 设计模式。

创建 Model 类

首先,我们定义一个简单的待办事项模型类 TodoItem,用于表示待办事项的信息。

// TodoItem.cs
public class TodoItem
{
    public int Id { get; set; }
    public string Title { get; set; }
    public bool IsCompleted { get; set; }

    public TodoItem(int id, string title, bool isCompleted)
    {
        Id = id;
        Title = title;
        IsCompleted = isCompleted;
    }

    public override string ToString()
    {
        return $"Id: {Id}, Title: {Title}, IsCompleted: {IsCompleted}";
    }
}

创建 ViewModel 类

接下来,我们创建一个 TodoViewModel 类,作为中介,负责将 Model 中的数据转换为 View 可以使用的格式,并处理来自 View 的用户输入。

// TodoViewModel.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class TodoViewModel : INotifyPropertyChanged
{
    private ObservableCollection todoItems;
    private string newTodoTitle;

    public event PropertyChangedEventHandler PropertyChanged;

    // 使用属性通知机制,当属性值发生变化时通知视图更新
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ObservableCollection TodoItems
    {
        get => todoItems;
        set
        {
            todoItems = value;
            OnPropertyChanged();
        }
    }

    public string NewTodoTitle
    {
        get => newTodoTitle;
        set
        {
            newTodoTitle = value;
            OnPropertyChanged();
        }
    }

    public TodoViewModel()
    {
        TodoItems = new ObservableCollection();
    }

    // 添加待办事项命令
    public void AddTodoItem()
    {
        if (!string.IsNullOrWhiteSpace(NewTodoTitle))
        {
            var newItem = new TodoItem(TodoItems.Count + 1, NewTodoTitle, false);
            TodoItems.Add(newItem);
            NewTodoTitle = string.Empty;
        }
    }

    // 删除待办事项命令
    public void RemoveTodoItem(TodoItem item)
    {
        TodoItems.Remove(item);
    }
}

创建 View 类

接下来,我们创建一个简单的 WPF 窗口 MainWindow.xaml,用于显示待办事项列表,并允许用户添加新的待办事项。



    
        
            
            

绑定 ViewModel 到 View

MainWindow.xaml.cs 中,我们将 TodoViewModel 绑定到 MainWindow

// MainWindow.xaml.cs
using System.Windows;

namespace TodoApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new TodoViewModel(); // 设置数据上下文为 TodoViewModel 实例
        }
    }
}

执行结果

运行上述代码后,用户可以看到一个简单的待办事项应用程序窗口。用户可以在文本框中输入新的待办事项标题,并点击“Add Todo”按钮将其添加到列表中。每个待办事项旁边都有一个“Remove”按钮,可以删除对应的待办事项。

MVVM 的高级用法

为了更好地理解 MVVM 的高级用法,我们可以进一步扩展上面的例子,引入更多复杂的场景和功能。

使用 ICommand 接口

在 ViewModel 中,我们可以使用 ICommand 接口来实现命令绑定,使代码更加清晰和易于维护。

// RelayCommand.cs
using System;
using System.Windows.Input;

public class RelayCommand : ICommand
{
    private readonly Action execute;
    private readonly Func canExecute;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action execute, Func canExecute = null)
    {
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return canExecute == null || canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        execute(parameter);
    }
} 
  

更新 ViewModel 类

我们在 TodoViewModel 中使用 RelayCommand 来实现命令绑定。

// TodoViewModel.cs
public class TodoViewModel : INotifyPropertyChanged
{
    private ObservableCollection todoItems;
    private string newTodoTitle;

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ObservableCollection TodoItems
    {
        get => todoItems;
        set
        {
            todoItems = value;
            OnPropertyChanged();
        }
    }

    public string NewTodoTitle
    {
        get => newTodoTitle;
        set
        {
            newTodoTitle = value;
            OnPropertyChanged();
        }
    }

    public ICommand AddTodoCommand { get; }
    public ICommand RemoveTodoCommand { get; }

    public TodoViewModel()
    {
        TodoItems = new ObservableCollection();
        AddTodoCommand = new RelayCommand(AddTodoItem);
        RemoveTodoCommand = new RelayCommand(RemoveTodoItem);
    }

    public void AddTodoItem(object parameter)
    {
        if (!string.IsNullOrWhiteSpace(NewTodoTitle))
        {
            var newItem = new TodoItem(TodoItems.Count + 1, NewTodoTitle, false);
            TodoItems.Add(newItem);
            NewTodoTitle = string.Empty;
        }
    }

    public void RemoveTodoItem(object parameter)
    {
        if (parameter is TodoItem item)
        {
            TodoItems.Remove(item);
        }
    }
}

更新 View 类

MainWindow.xaml 中,我们使用命令绑定来调用 AddTodoCommandRemoveTodoCommand



    
        
            
            

执行结果

运行上述代码后,用户可以看到一个简单的待办事项应用程序窗口。用户可以在文本框中输入新的待办事项标题,并点击“Add Todo”按钮将其添加到列表中。每个待办事项旁边都有一个“Remove”按钮,可以删除对应的待办事项。

MVVM 的优缺点

优点

  1. 分离关注点:MVVM 将业务逻辑、数据和 UI 分离,使得代码更易于理解和维护。
  2. 可测试性:由于 ViewModel 不依赖于具体的 UI 控件,因此可以更容易地编写单元测试。
  3. 数据绑定:MVVM 支持双向数据绑定,使得 UI 和数据之间的同步变得更加简单。
  4. 命令模式:通过使用 ICommand 接口,可以将命令绑定到 UI 控件,使代码更加清晰和易于维护。

缺点

  1. 学习曲线:对于初学者来说,MVVM 模式可能需要一些时间来掌握其概念和用法。
  2. 复杂性增加:在某些情况下,过度使用 MVVM 可能会使代码变得复杂,尤其是当嵌套层次较深时。
  3. 性能问题:虽然 MVVM 本身不会导致性能问题,但在某些极端情况下,频繁的数据绑定可能会带来一定的开销。

应用场景

MVVM 在许多实际应用场景中都非常有用,以下是一些常见的应用场景:

  1. WPF/Silverlight 应用程序:MVVM 是 WPF 和 Silverlight 应用程序的标准设计模式,能够显著提高代码的可维护性和测试性。
  2. Xamarin.Forms 应用程序:MVVM 也可以用于 Xamarin.Forms 应用程序,帮助开发者构建跨平台移动应用。
  3. 桌面应用程序:MVVM 可以用于构建复杂的桌面应用程序,如企业级管理系统。
  4. Web 应用程序:虽然 MVVM 主要用于客户端应用程序,但也可以用于构建单页应用程序(SPA),如 Angular 或 Vue.js 应用程序。

总结

MVVM(Model-View-ViewModel)是一种非常强大的设计模式,它能够有效地分离业务逻辑、数据和 UI,提高代码的可维护性和测试性。通过使用 MVVM,开发者可以以一种简洁的方式实现复杂的应用程序,适用于多种类型的应用场景。

 

你可能感兴趣的:(C#,面试问题高级,microsoft,c#,开发语言,设计模式,面试,MVVM,MVC)