通过应用软件架构模式开发android应用程序始终是开发人员的首选。架构模式为项目文件提供了模块化,并确保所有代码都包含在单元测试中。它使开发人员将来可以轻松完成维护软件和扩展应用程序功能的任务。有一些架构在开发人员中非常流行,其中之一就是“模型—视图—控制器(MVC)模式”。 MVC模式建议将代码分为3个部分。在创建应用程序的类/文件时,开发人员必须将其分类为以下三层之一:
- 型号:此组件存储应用程序数据。它不具备有关接口的知识。该模型负责处理域逻辑(实际业务规则)以及与数据库和网络层的通信。
- 查看:它 是个 UI(用户界面)层,其中包含在屏幕上可见的组件。此外,它提供了存储在模型中的数据的可视化,并向用户提供了交互。
- 控制器:此组件建立视图与模型之间的关系。它包含核心应用程序逻辑,并通知用户行为并根据需要更新模型。
尽管应用MVC架构为应用程序提供模块化设计,但代码层确实相互依赖。在这种模式下,视图和控制器都取决于模型。可以使用多种方法在项目中应用MVC模式:
- 方法1:活动和片段可以执行Controller的角色,并负责更新View。
- 方法2:将活动或片段用作视图和控制器,而Model将是一个单独的类,不会扩展任何Android类。
在MVC架构中,应用程序数据由控制器更新,而View获取数据。由于Model组件是分离的,因此可以独立于UI进行测试。此外,如果View层遵循单一职责原则,则它们的作用只是为每个用户事件更新Controller,并仅显示来自Model的数据,而无需实现任何业务逻辑。在这种情况下,UI测试应该足以涵盖View的功能。
MVC架构示例
为了更清楚地了解MVC架构模式的实现,这是一个android应用程序的简单示例。该应用程序将具有3个按钮,每个按钮都显示用户单击该特定按钮的次数。为了开发该应用程序,已按照以下方式分离了代码:
- Controller和View将由Activity处理。每当用户单击按钮时,活动都会指示模型处理进一步的操作。该活动将充当观察员。
- 该模型将是一个单独的类,其中包含要显示的数据。数据的操作将由此类的功能执行,并且在更新数据的值之后,此Observable类将有关更改的信息通知给Observer(Activity) 。
以下是使用MVC架构模式的此android应用程序的完整分步实施:
Note: Following steps are performed on Android Studio version 4.0
步骤1:创建一个新项目
- 单击文件,然后单击新建=>新建项目。
- 选择清空活动
- 选择语言作为Java/科特林
- 根据需要选择最小的SDK。
步骤2:修改String.xml文件
此文件中列出了活动中使用的所有字符串。
XML
GfG | MVC Architecture
MVC Architecture Pattern
Button_1
Count:0
XML
Java
import java.util.*;
public class Model extends Observable {
// declaring a list of integer
private List List;
// constructor to initialize the list
public Model(){
// reserving the space for list elements
List = new ArrayList(3);
// adding elements into the list
List.add(0);
List.add(0);
List.add(0);
}
// defining getter and setter functions
// function to return appropriate count
// value at correct index
public int getValueAtIndex(final int the_index) throws IndexOutOfBoundsException{
return List.get(the_index);
}
// function to make changes in the activity button's
// count value when user touch it
public void setValueAtIndex(final int the_index) throws IndexOutOfBoundsException{
List.set(the_index,List.get(the_index) + 1);
setChanged();
notifyObservers();
}
}
Kotlin
import java.util.*
import kotlin.collections.ArrayList
class Model : Observable() {
// declaring a list of integer
val List: MutableList
// constructor to initialize the list
init {
// reserving the space for list elements
List = ArrayList(3)
// adding elements into the list
List.add(0)
List.add(0)
List.add(0)
}
// defining getter and setter functions
// function to return appropriate count
// value at correct index
@Throws(IndexOutOfBoundsException::class)
fun getValueAtIndex(the_index: Int): Int {
return List[the_index]
}
// function to make changes in the activity button's
// count value when user touch it
@Throws(IndexOutOfBoundsException::class)
fun setValueAtIndex(the_index: Int) {
List[the_index] = List[the_index] + 1
setChanged()
notifyObservers()
}
}
Java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.util.Observable;
import java.util.Observer;
public class MainActivity extends AppCompatActivity implements Observer, View.OnClickListener {
// creating object of Model class
private Model myModel;
// creating object of Button class
private Button Button1;
private Button Button2;
private Button Button3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// creating relationship between the
// observable Model and the
// observer Activity
myModel = new Model();
myModel.addObserver(this);
// assigning button IDs to the objects
Button1 = findViewById(R.id.button);
Button2 = findViewById(R.id.button2);
Button3 = findViewById(R.id.button3);
// transfer the control to Onclick() method
// when a button is clicked by passing
// argument "this"
Button1.setOnClickListener(this);
Button2.setOnClickListener(this);
Button3.setOnClickListener(this);
}
@Override
// calling setValueAtIndex() method
// by passing appropriate arguments
// for different buttons
public void onClick(View v) {
switch(v.getId()){
case R.id.button:
myModel.setValueAtIndex(0);
break;
case R.id.button2:
myModel.setValueAtIndex(1);
break;
case R.id.button3:
myModel.setValueAtIndex(2);
break;
}
}
@Override
// function to update the view after
// the values are modified by the model
public void update(Observable arg0, Object arg1) {
// changing text of the buttons
// according to updated values
Button1.setText("Count: "+myModel.getValueAtIndex(0));
Button2.setText("Count: "+myModel.getValueAtIndex(1));
Button3.setText("Count: "+myModel.getValueAtIndex(2));
}
}
Kotlin
import android.os.Bundle
import android.view.View
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import java.util.*
class MainActivity : AppCompatActivity(), Observer, View.OnClickListener {
// creating object of Model class
var myModel: Model? = null
// creating object of Button class
var Button1: Button? = null
var Button2: Button? = null
var Button3: Button? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// creating relationship between the
// observable Model and the
// observer Activity
myModel = Model()
myModel!!.addObserver(this)
// assigning button IDs to the objects
Button1 = findViewById(R.id.button)
Button2 = findViewById(R.id.button2)
Button3 = findViewById(R.id.button3)
// transfer the control to Onclick() method
// when a button is clicked by passing
// argument "this"
Button1?.setOnClickListener(this)
Button2?.setOnClickListener(this)
Button3?.setOnClickListener(this)
}
// calling setValueAtIndex() method
// by passing appropriate arguments
// for different buttons
override fun onClick(v: View) {
when (v.id) {
R.id.button -> myModel?.setValueAtIndex(0)
R.id.button2 -> myModel?.setValueAtIndex(1)
R.id.button3 -> myModel?.setValueAtIndex(2)
}
}
// function to update the view after
// the values are modified by the model
override fun update(arg0: Observable, arg1: Any?) {
// changing text of the buttons
// according to updated values
Button1!!.text = "Count: " + myModel!!.getValueAtIndex(0)
Button2!!.text = "Count: " + myModel!!.getValueAtIndex(1)
Button3!!.text = "Count: " + myModel!!.getValueAtIndex(2)
}
}
步骤3:使用activity_main.xml文件
打开activity_main.xml文件,并向其中添加3个按钮,这些按钮将根据用户单击它的次数显示计数值。以下是用于设计适当活动布局的代码。
XML格式
步骤4:创建模型类
创建一个名为Model的新类,以分隔所有数据及其操作。该类将不知道View类的存在。
Java
import java.util.*;
public class Model extends Observable {
// declaring a list of integer
private List List;
// constructor to initialize the list
public Model(){
// reserving the space for list elements
List = new ArrayList(3);
// adding elements into the list
List.add(0);
List.add(0);
List.add(0);
}
// defining getter and setter functions
// function to return appropriate count
// value at correct index
public int getValueAtIndex(final int the_index) throws IndexOutOfBoundsException{
return List.get(the_index);
}
// function to make changes in the activity button's
// count value when user touch it
public void setValueAtIndex(final int the_index) throws IndexOutOfBoundsException{
List.set(the_index,List.get(the_index) + 1);
setChanged();
notifyObservers();
}
}
科特林
import java.util.*
import kotlin.collections.ArrayList
class Model : Observable() {
// declaring a list of integer
val List: MutableList
// constructor to initialize the list
init {
// reserving the space for list elements
List = ArrayList(3)
// adding elements into the list
List.add(0)
List.add(0)
List.add(0)
}
// defining getter and setter functions
// function to return appropriate count
// value at correct index
@Throws(IndexOutOfBoundsException::class)
fun getValueAtIndex(the_index: Int): Int {
return List[the_index]
}
// function to make changes in the activity button's
// count value when user touch it
@Throws(IndexOutOfBoundsException::class)
fun setValueAtIndex(the_index: Int) {
List[the_index] = List[the_index] + 1
setChanged()
notifyObservers()
}
}
步骤5:在MainActivity文件中定义View和Controller的功能
此类将建立View与Model之间的关系。 View将使用模型提供的数据,并在活动中进行适当的更改。
Java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.util.Observable;
import java.util.Observer;
public class MainActivity extends AppCompatActivity implements Observer, View.OnClickListener {
// creating object of Model class
private Model myModel;
// creating object of Button class
private Button Button1;
private Button Button2;
private Button Button3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// creating relationship between the
// observable Model and the
// observer Activity
myModel = new Model();
myModel.addObserver(this);
// assigning button IDs to the objects
Button1 = findViewById(R.id.button);
Button2 = findViewById(R.id.button2);
Button3 = findViewById(R.id.button3);
// transfer the control to Onclick() method
// when a button is clicked by passing
// argument "this"
Button1.setOnClickListener(this);
Button2.setOnClickListener(this);
Button3.setOnClickListener(this);
}
@Override
// calling setValueAtIndex() method
// by passing appropriate arguments
// for different buttons
public void onClick(View v) {
switch(v.getId()){
case R.id.button:
myModel.setValueAtIndex(0);
break;
case R.id.button2:
myModel.setValueAtIndex(1);
break;
case R.id.button3:
myModel.setValueAtIndex(2);
break;
}
}
@Override
// function to update the view after
// the values are modified by the model
public void update(Observable arg0, Object arg1) {
// changing text of the buttons
// according to updated values
Button1.setText("Count: "+myModel.getValueAtIndex(0));
Button2.setText("Count: "+myModel.getValueAtIndex(1));
Button3.setText("Count: "+myModel.getValueAtIndex(2));
}
}
科特林
import android.os.Bundle
import android.view.View
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import java.util.*
class MainActivity : AppCompatActivity(), Observer, View.OnClickListener {
// creating object of Model class
var myModel: Model? = null
// creating object of Button class
var Button1: Button? = null
var Button2: Button? = null
var Button3: Button? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// creating relationship between the
// observable Model and the
// observer Activity
myModel = Model()
myModel!!.addObserver(this)
// assigning button IDs to the objects
Button1 = findViewById(R.id.button)
Button2 = findViewById(R.id.button2)
Button3 = findViewById(R.id.button3)
// transfer the control to Onclick() method
// when a button is clicked by passing
// argument "this"
Button1?.setOnClickListener(this)
Button2?.setOnClickListener(this)
Button3?.setOnClickListener(this)
}
// calling setValueAtIndex() method
// by passing appropriate arguments
// for different buttons
override fun onClick(v: View) {
when (v.id) {
R.id.button -> myModel?.setValueAtIndex(0)
R.id.button2 -> myModel?.setValueAtIndex(1)
R.id.button3 -> myModel?.setValueAtIndex(2)
}
}
// function to update the view after
// the values are modified by the model
override fun update(arg0: Observable, arg1: Any?) {
// changing text of the buttons
// according to updated values
Button1!!.text = "Count: " + myModel!!.getValueAtIndex(0)
Button2!!.text = "Count: " + myModel!!.getValueAtIndex(1)
Button3!!.text = "Count: " + myModel!!.getValueAtIndex(2)
}
}
输出
MVC架构模式的优势
- MVC模式增强了代码的可测试性,并且由于它高度支持关注点分离,因此使其更易于实现新功能。
- 由于Model和Controller不扩展或不使用任何Android类,因此可以进行单元测试。
- 如果View遵守单一职责原则,则可以通过UI测试来检查View的功能(更新控制器并显示来自模型的数据,而无需实现域逻辑)
MVC架构模式的缺点
- 即使正确应用了MVC,代码层也相互依赖。
- 没有用于处理UI逻辑的参数,即如何显示数据。