首页 > 其他分享 >一文弄懂MVC、MVP和MVVM

一文弄懂MVC、MVP和MVVM

时间:2024-11-03 18:16:09浏览次数:5  
标签:MVP MVVM MVC fun import android id todos View

一、MVC

1.什么是MVC

M可以由数据类(结合数据文件)实现;

C控制/调度逻辑业务逻辑【业务功能实现】,由Activity实现;

Vxml布局文件UI逻辑【UI逻辑由Activity实现】;

目前很多企业都采用敏捷开发的开发方式,在的用户界面逻辑的变更频率往往高于业务逻辑。 如果将表示界面代码和业务逻辑组合在单个对象中,则每次更改用户界面时都必须修改包含业务逻辑的对象, 这常常会引发错误,并且需要在每次进行细微的用户界面更改后重新测试业务逻辑。

将代码实现分为三部分,将容易变化和不易变化的部分分离,实现分离关注点,方便后续代码维护和软件迭代。

2.如何实现MVC

(1)Model

package com.example.todoproject

data class TodoItem(
    var id: Int,
    var title: String,
    var description: String,
    var isCompleted: Boolean
)
package com.example.todoproject

class TodoDao(todoListActivity: TodoListActivity) {
    private val todos = mutableListOf<TodoItem>()

    init {
        // 初始化一些模拟数据
        todos.add(TodoItem(1, "Task 1", "Description of Task 1", false))
        todos.add(TodoItem(2, "Task 2", "Description of Task 2", false))
        todos.add(TodoItem(3, "Task 3", "Description of Task 3", false))
    }

    fun insertTodo(todo: TodoItem): Long {
        todo.id = todos.size + 1
        todos.add(todo)
        return todo.id.toLong()
    }

    fun getAllTodos(): List<TodoItem> {
        return todos
    }

    fun updateTodo(todo: TodoItem) {
        val index = todos.indexOfFirst { it.id == todo.id }
        if (index!= -1) {
            todos[index] = todo
        }
    }
}

(2)View和Controller

package com.example.todoproject

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity

class TodoListActivity : AppCompatActivity(), View.OnClickListener {

    private lateinit var editTextTitle: EditText
    private lateinit var editTextDescription: EditText
    private lateinit var buttonAddTodo: Button
    private lateinit var listViewTodos: ListView
    private lateinit var todoAdapter: TodoAdapter
    private lateinit var todoDao: TodoDao

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_todo_list)

        editTextTitle = findViewById(R.id.editTextTitle)
        editTextDescription = findViewById(R.id.editTextDescription)
        buttonAddTodo = findViewById(R.id.buttonAddTodo)
        listViewTodos = findViewById(R.id.listViewTodos)

        buttonAddTodo.setOnClickListener(this)

        todoDao = TodoDao(this)

        val todos = todoDao.getAllTodos()
        todoAdapter = TodoAdapter(this, todos)
        listViewTodos.adapter = todoAdapter
    }

    override fun onClick(v: View) {
        if (v.id == R.id.buttonAddTodo) {
            val title = editTextTitle.text.toString()
            val description = editTextDescription.text.toString()
            val todo = TodoItem(0, title, description, false)
            val id = todoDao.insertTodo(todo)
            todo.id = id.toInt()
            todoAdapter.addTodo(todo)
            editTextTitle.text.clear()
            editTextDescription.text.clear()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
    }
}
package com.example.todoproject

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.TextView

import java.util.*

class TodoAdapter(context: Context, todos: List<TodoItem>) : ArrayAdapter<TodoItem>(context, 0, todos) {
    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        var view = convertView
        if (view == null) {
            view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false)
        }
        val textView = view!!.findViewById<TextView>(android.R.id.text1)
        val todo = getItem(position)
        textView.text = todo?.title
        return view
    }

    fun addTodo(todo: TodoItem) {
        add(todo)
        notifyDataSetChanged()
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <EditText
        android:id="@+id/editTextTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <EditText
        android:id="@+id/editTextDescription"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/buttonAddTodo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add Todo" />
    <ListView
        android:id="@+id/listViewTodos"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

3.MVC的优缺点

优点:简单粗暴,适合小项目

缺点:View和Controller之间职责不清晰:我们会发现,View和Controller均依赖于Model。 但是,Model既不依赖于View,也不依赖于Controller,尤其在Android中,View和Controller都在Activity中实现,导致View和Controller的逻辑并不清晰,导致职责分离不彻底,使我们最初使用MVC的目的并没有实现

二、MVP

1.什么是MVP

  • M(model)代表的是将会显示在view(UI)中的数据。
  • V(view)是显示数据(model)和UI逻辑。
  • P(presenter)扮演的是“中间人”的作用(就如MVC中的controller),且presenter同时引用view和model。作为 View 和 Model 之间的中介,负责处理用户输入和更新 View。Presenter 接收来自 View 的用户输入,调用 Model 中的方法进行数据处理,并将结果返回给 View 进行显示。

MVC 和 MVP 的区别就是,在 MVP 中 M 和 V 没有直接通信,从而实现了三者的解耦合

2.如何实现MVP

1.View

import com.example.todoproject.TodoItem

interface TodoView {
    fun showTodos(todos: List<TodoItem>)
    fun showError(message: String)
}
package com.example.todoprojectmvp

import TodoAdapter
import TodoPresenter
import TodoPresenterImpl
import TodoView
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.ListView
import android.widget.Toast
import com.example.todoproject.TodoDao
import com.example.todoproject.TodoItem

class TodoListActivity : AppCompatActivity() , TodoView, View.OnClickListener {
    private lateinit var editTextTitle: EditText
    private lateinit var editTextDescription: EditText
    private lateinit var buttonAddTodo: Button
    private lateinit var listViewTodos: ListView
    private lateinit var presenter: TodoPresenter
    private lateinit var todoAdapter: TodoAdapter
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_todo_list)

        editTextTitle = findViewById(R.id.editTextTitle)
        editTextDescription = findViewById(R.id.editTextDescription)
        buttonAddTodo = findViewById(R.id.buttonAddTodo)
        listViewTodos = findViewById(R.id.listViewTodos)

        buttonAddTodo.setOnClickListener(this)

        presenter = TodoPresenterImpl(this)

        // 初始化适配器
        todoAdapter = TodoAdapter(this, emptyList())
        listViewTodos.adapter = todoAdapter
    }

    override fun onResume() {
        super.onResume()
        presenter.loadTodos()
    }

    override fun showTodos(todos: List<TodoItem>) {
        // 更新列表视图
        todoAdapter.todos = todos
        todoAdapter.notifyDataSetChanged()
    }

    override fun showError(message: String) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }

    override fun onClick(v: View?) {
        if (v != null) {
            if (v.id == R.id.buttonAddTodo) {
                val title = editTextTitle.text.toString()
                val description = editTextDescription.text.toString()
                presenter.addTodo(title, description)
                editTextTitle.text.clear()
                editTextDescription.text.clear()
            }
        }
    }

}
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
import com.example.todoproject.TodoItem
import com.example.todoprojectmvp.R

class TodoAdapter(private val context: Context, var todos: List<TodoItem>) : BaseAdapter() {

    override fun getCount(): Int {
        return todos.size
    }

    override fun getItem(position: Int): TodoItem {
        return todos[position]
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        var view = convertView
        if (view == null) {
            view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false)
        }
        val textView = view!!.findViewById<TextView>(android.R.id.text1)
        val todo = getItem(position)
        textView.text = todo.title
        return view
    }
}

2.Presenter

interface TodoPresenter {
    fun loadTodos()
    fun addTodo(title: String, description: String)
}
import com.example.todoproject.TodoDao
import com.example.todoproject.TodoItem
import com.example.todoprojectmvp.TodoListActivity

class TodoPresenterImpl(private val view: TodoView) : TodoPresenter {
    private lateinit var todoDao: TodoDao


    init {
        todoDao = TodoDao(view as TodoListActivity)
    }

    override fun loadTodos() {
        val todos = todoDao.getAllTodos()
        view.showTodos(todos)
    }

    override fun addTodo(title: String, description: String) {
        val todo = TodoItem(0, title, description, false)
        val id = todoDao.insertTodo(todo)
        todo.id = id.toInt()
        loadTodos()
    }
}

3.Model

package com.example.todoproject

data class TodoItem(
    var id: Int,
    var title: String,
    var description: String,
    var isCompleted: Boolean
)
package com.example.todoproject

import com.example.todoprojectmvp.TodoListActivity

class TodoDao(todoListActivity: TodoListActivity) {
    private val todos = mutableListOf<TodoItem>()

    init {
        // 初始化一些模拟数据
        todos.add(TodoItem(1, "Task 1", "Description of Task 1", false))
        todos.add(TodoItem(2, "Task 2", "Description of Task 2", false))
        todos.add(TodoItem(3, "Task 3", "Description of Task 3", false))
    }

    fun insertTodo(todo: TodoItem): Long {
        todo.id = todos.size + 1
        todos.add(todo)
        return todo.id.toLong()
    }

    fun getAllTodos(): List<TodoItem> {
        return todos
    }

    fun updateTodo(todo: TodoItem) {
        val index = todos.indexOfFirst { it.id == todo.id }
        if (index!= -1) {
            todos[index] = todo
        }
    }
}

3.MVP的优缺点

优点:实现分离,实现了三种职责之间的解耦

缺点:P可能会出现代码过于繁杂的情况:View的改变和Model的改变都需要P进行逻辑处理,例如在Todo的例子中,当用户点击AddTODO时,p从View获取数据,并需要代码手动添加到Model中,同时,需要代码手动更新View中的TodoList,导致P中代码的冗杂。

一、什么是MVVM?

MVVM 即 Model-View-ViewModel,是一种用于构建用户界面的软件架构模式。它的主要目的是将用户界面的开发与业务逻辑的开发分离开来,提高代码的可维护性、可测试性和可扩展性。

Model 代表数据模型,负责存储和管理应用程序的数据。

View 是用户界面,负责展示数据和接收用户输入。

ViewModel 则是连接 Model 和 View 的桥梁,它将 Model 中的数据转换为 View 可以显示的形式,并处理 View 中的用户输入,将其转换为对 Model 的操作。

二、为什么使用MVVM架构?

View和Model进行双向绑定(data-binding), 两者之间有一方发生变化则会反应到另一方上;

1.优点:

1.清晰的结构划分

2.快速响应变化:由于 View 和 Model 之间通过 ViewModel 进行解耦,当需求变化时,可以只修改相应的部分,而不会影响到其他部分

2.缺点:

1.学习成本(略)高

2.性能问题:例如,数据频繁变化,界面频繁变化

3.代码复杂,调试困难

三、MVVM架构如何实现的?

1.类图

2.示例代码

(1)Model

public class TodoItem {
    private int id;
    private String title;
    private boolean completed;

    public TodoItem(int id, String title, boolean completed) {
        this.id = id;
        this.title = title;
        this.completed = completed;
    }

    public int getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public boolean isCompleted() {
        return completed;
    }

    public void setCompleted(boolean completed) {
        this.completed = completed;
    }
}

(2)ViewModel

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import com.example.todoproject.TodoItem
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class TodoViewModel(private val todoAdapter: TodoAdapter, application: Application) : AndroidViewModel(application) {
    private val repository: TodoRepository
    var todoItems: LiveData<List<TodoItem>>


    init {
        repository = TodoRepository(application)
        todoItems = repository.getTodoItems()
    }

    fun addTodo(todoItem: TodoItem) {
        repository.insertTodo(todoItem)
        todoItems = repository.getTodoItems()
        updateTodo(todoItem)
    }

    fun updateTodo(todoItem: TodoItem) {
        CoroutineScope(Dispatchers.IO).launch {
            repository.updateTodo(todoItem)
            withContext(Dispatchers.Main) {
                todoAdapter.notifyDataSetChanged()
            }
        }
    }

}

(3)View

package com.example.todoprojectmvvm

import TodoAdapter
import TodoViewModel
import android.content.ContentValues.TAG
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.ListView
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.todoproject.TodoItem

class TodoListActivity : AppCompatActivity() {
    private lateinit var editTextTitle: EditText
    private lateinit var editTextDescription: EditText
    private lateinit var buttonAddTodo: Button
    private lateinit var todoViewModel: TodoViewModel
    private lateinit var todoAdapter: TodoAdapter
    private lateinit var listViewTodos: ListView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_todo_list)

        editTextTitle = findViewById(R.id.editTextTitle)
        editTextDescription = findViewById(R.id.editTextDescription)
        buttonAddTodo = findViewById(R.id.buttonAddTodo)
        listViewTodos = findViewById(R.id.listViewTodos)

        // 创建 ViewModel 并传递 Adapter
        todoAdapter = TodoAdapter(this, emptyList())
        todoViewModel = TodoViewModel( todoAdapter, application)
        listViewTodos.adapter = todoAdapter

        todoViewModel.todoItems.observe(this, Observer { todoItems ->
            todoAdapter.updateData(todoItems)
        })

        buttonAddTodo.setOnClickListener {
            val title = editTextTitle.text.toString()
            val description = editTextDescription.text.toString()
            val todoItem = TodoItem(0, title, description, false)
            todoViewModel.addTodo(todoItem)
            editTextTitle.text.clear()
            editTextDescription.text.clear()
        }
    }
}
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
import com.example.todoproject.TodoItem

class TodoAdapter(private val context: Context, var todos: List<TodoItem>) : BaseAdapter() {

    override fun getCount(): Int {
        return todos.size
    }

    override fun getItem(position: Int): TodoItem {
        return todos[position]
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        var view = convertView
        if (view == null) {
            view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false)
        }
        val textView = view!!.findViewById<TextView>(android.R.id.text1)
        val todo = getItem(position)
        textView.text = todo.title
        return view
    }
    fun updateData(newTodos: List<TodoItem>) {
        todos = newTodos
        notifyDataSetChanged()
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <EditText
        android:id="@+id/editTextTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <EditText
        android:id="@+id/editTextDescription"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/buttonAddTodo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add Todo" />
    <ListView
        android:id="@+id/listViewTodos"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

致此,MVC、MVP和MVVM讲解结束,有任何疑问,欢迎提问 

标签:MVP,MVVM,MVC,fun,import,android,id,todos,View
From: https://blog.csdn.net/m0_60892159/article/details/143468326

相关文章

  • WPF datagrid export command in mvvm and customize delegatecommand inherited from
    publicclassDelCommand:ICommand{publiceventEventHandlerCanExecuteChanged{add{CommandManager.RequerySuggested+=value;}remove{CommandManager.RequerySuggested-=value;......
  • asp.net dotnet razor page mvc 过滤器 数据验证过滤器 数据库事务过滤器
    asp.netdotnetrazorpagemvc过滤器数据验证过滤器数据库事务过滤器Program.cs注册过滤器services.AddRazorPages(opt=>{opt.Conventions.ConfigureFilter(newDbContextTransactionPageFilter());opt.Conventions.ConfigureFilter(n......
  • WPF datagrid implement multi select via behavior selectionchanged event in MVVM
    <DataGridItemsSource="{BindingBooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"CanUserAddRows="False"AutoGenerateColumns="False"SelectionMode="Extended">......
  • SpringMVC笔记 一万字
    此笔记来自于B站尚硅谷文章目录一、SpringMVC简介1、什么是MVC2、什么是SpringMVC3、SpringMVC的特点二、HelloWorld1、开发环境2、创建maven工程a>添加web模块b>打包方式:warc>引入依赖3、配置web.xmla>默认配置方式b>扩展配置方式4、创建请求控制器5、创建sprin......
  • springmvc请求源码流程解析(二)
        Spring官网的MVC模块介绍:SpringWebMVC是基于ServletAPI构建的原始Web框架,从一开始就已包含在Spring框架中。正式名称“SpringWebMVC”来自其源模块的名称(spring-webmvc),但它通常被称为SpringMVC。    从Servlet到SpringMVC:    最典型的MVC就是J......
  • 使用asp.net mvc 过程中 参数传递的问题记录。
    环境:asp.netMVC需求:要实现主从表数据存储,主表为结构化信息,附表为对应的图片。实现过程:页面中当用户在新建数据的时候,未保存时没有主表的主键,同时用户也会选择要上传的图片一同保存。 使用ajaxfileupload.js实现多文件上传,上传之后通过window.URL.createObjectURL将上传......
  • InnoDB存储引擎、多版本并发控制(MVCC)简介、Redis简介
    (一)InnoDB存储引擎InnoDB是MySQL最常用的存储引擎之一,有支持事务处理、行级锁定和外键约束等高级功能而著称。1、InnoDB架构物理结构表空间:InnoDB的数据存储空间在表空间中,表空间可以分为系统表空间、文件表空间和通用表空间。系统表空间:默认存储在ibdata1文件中,包含系统......
  • CommunityToolkit.Mvvm中的Ioc
    什么是Ioc在软件工程中,控制反转(IoC)是一种设计原则,其中计算机程序的自定义编写部分从外部源(例如框架)接收控制流。术语“反转”是历史性的:与过程式编程相比,具有这种设计的软件架构“反转”了控制。在过程式编程中,程序的自定义代码调用可重用库来处理通用任务,但在控制反转的情况下,是......
  • 【SpringMVC】web服务器,访问失败的问题,SpringMVC,建立连接,请求
    【web服务器】web服务器可以对http协议进行封装,程序员不需要直接对http协议进行操作(不需要去写复杂的网络编程代码),让web开发更加便捷,所以它也有「WWW服务器」的称呼常见的web服务器:Tomcat,Jboss,IIS等SpringBoot内置了Tomcat服务器,无需配置即可使用Tomcat默认端口是「8080」......
  • 【SpringMVC】传递json,获取url参数,上传文件
    【传递json数据】【json概念】一种轻量级数据交互格式,有自己的格式和语法,使用文本表示一个对象或数组的信息,其本质上是字符串,负责在不同的语言中数据传递与交换json数据以字符串的形式体现【json字符串与Java对象互转】我们需要在pom.xml中增加对json的依赖【对象转jso......