使用 MVC 架构进行 Java 编程






4.50/5 (11投票s)
本文使用MVC框架构建基于Java的桌面应用程序或企业解决方案。
引言
本文是关于Java应用程序开发中的MVC框架,从用于基本程序的桌面应用程序到用Java编写的企业解决方案。在本文中,将涵盖MVC框架的基本概念。MVC框架用于分离数据访问层、业务逻辑代码和必须定义和设计的图形用户界面,以允许用户与应用程序交互。此应用程序包含三个部分:
- 模型 - 框架的这一部分用于存储应用程序的数据,例如数据库、文本数据、文件和/或其他Web资源。
- 视图 - 这是应用程序的图形用户界面。它将包含不同的按钮、文本框和其他控件,以允许用户与应用程序交互,根据他正在使用的软件类型完成他的项目。
- 控制器 - 实际的后端代码构成了框架的控制器。控制器控制来自用户或从模型发送给用户的数据。
这设置了一个验证条件,因为数据流(来自用户或发送给用户)总是在控制器上进行验证。这就是为什么它通过消除任何无效数据输入或未经授权从应用程序数据源删除数据的机会,使数据更加一致的原因。
MVC的背景
在本简短部分中,我将尝试提供MVC框架的基本概述。本节不是针对Java特定的框架,而是针对MVC框架本身。初学者可能对了解MVC框架是什么、它如何交互以及它如何提高软件开发效率感兴趣。但是,如果您已经了解MVC框架,那么您就不需要阅读本节,请继续阅读下一节中的应用程序开发。
MVC框架通常是用于实现用户界面的软件架构的术语。您可以将软件的源代码分成三个不同的层:
- 模型
- 视图
- 控制器 (Controller)
之后,您可以单独开发它们。这样,一旦您的应用程序达到企业级别并且您的源代码看起来有点混乱且无法调试,您就不必为此头疼了。在MVC中,您的所有三个层都是独立的,这样您就可以单独控制、开发、调试或向所有层添加功能。
MVC框架的一个非常好的特性是它向用户隐藏了数据访问层。也就是说,数据访问层或数据从不直接由用户(从界面)调用。这样,用户必须执行他被允许的操作。此功能允许开发人员创建允许访问数据的用户组或角色;例如管理员、访客等。
这个框架的另一个优点是它不会让应用程序变得过于复杂,并且应用程序的所有三个部分不会在单个源代码包中相互干扰。因此,您始终知道问题发生在哪里。常见的例子包括:
- 当您知道问题出在数据访问层时。例如,在数据库中,您允许了`null`条目,所以现在垃圾邮件用户将能够使数据不一致并导致冗余问题。您可以编辑数据访问层,以便将列定义为不允许`null`值。
- 当视图未正确显示数据时。例如,数据绑定不准确,或者日期和时间值的格式不正确。您只需编辑应用程序的视图部分即可使其再次工作,而不是编辑包含后端代码和/或数据访问代码的不同变量的整个页面。
- 当逻辑定义不正确时。有时数据是正确的,视图正确地绑定到资源,但应用程序的逻辑不正确。这种类型的问题很难发现,因为开发人员必须通过粗略尝试或使用IDE调试代码并在某些位置设置几个断点来思考代码在哪里出错。
这些是MVC框架用于开发软件应用程序的一些优点。在视觉表示中,MVC框架的工作方式如下:
图像清楚地表明用户无法自行连接到数据源。相反,他必须与顶层交互才能访问数据。例如,视图,他与按钮交互,然后按钮调用控制器对数据执行操作(如果需要)。但是用户无法直接访问数据。这使得数据源对潜在用户来说是安全的;无论如何,总有潜在用户的威胁。
我写了一篇关于ASP.NET MVC框架的文章,我在其中演示了MVC框架,然后深入探讨了ASP.NET的MVC框架;就像这篇一样。所以,如果你有兴趣了解更多关于MVC框架的知识,你可能会有兴趣阅读那篇文章一次;只是MVC部分,而不是ASP.NET部分。你可以在这里阅读那篇文章,你也可以在那里发布关于那篇文章的任何查询或问题。
构建应用程序
现在来到实现此框架并构建基于 Java 应用程序的实际部分。在接下来的步骤中,我将向您展示如何(使用此框架)创建从简单的 Hello World 应用程序到复杂程度不亚于使用 Java 的企业级应用程序。
设置环境 - 适用于 Java 初学者
要开发Java应用程序,您需要设置一个环境。环境需要一个IDE;用于编写源代码并将所需的库管理到一个单一包中,目前流行的一些是:
- Eclipse for Java - Eclipse是广泛使用的Java IDE,它也支持其他语言,但由于我们讨论的是Java应用程序,所以我只强调了Java。
- Oracle的NetBeans - NetBeans是在Oracle许可证下开发的IDE,主要由初学者使用,因为它通过拖放功能帮助他们创建GUI。我也使用NetBeans进行Java开发,对于Android开发我更喜欢Eclipse。您可以根据自己的喜好选择。
以及Java SDK。现在,这取决于您要开发的应用程序级别,有多种类型的Java SDK可供您选择。我正在使用Java SE SDK,它满足了我的要求。以下是可供下载的Java SDK列表,以及流行的版本:
- Java SE - 标准版。非常适合小型应用程序,例如桌面应用程序或其他不太复杂的应用程序。
- Java EE - 企业版。如果您要开发企业应用程序并且程序应该很复杂,则应优先选择Java EE而不是Java SE。
- Java ME - 千年版。它用于开发移动应用程序,例如*.jar*应用程序和其他要在移动设备上运行的项目。它应该被使用,因为它需要较少的内存和较小的堆大小才能运行应用程序,因此适用于移动应用程序编程。
- 然后它们继续延伸到电视、卡片等等。在此处了解更多信息。
您可以下载任何SDK,Java语言都是相似的。因此,我文章中的代码在任何情况下都非常适合您。您可以在计算机上下载并安装SDK。完成此步骤后,您可以继续进行编程。
IDE 的安装 需要声明一个 JAVA_HOME
系统变量。这是一个简单的任务;对于初学者来说有点令人困惑。进入我的电脑属性,然后在高级系统设置中找到环境变量。在其中,创建一个新的系统变量并将其命名为 JAVA_HOME
,其值必须是 bin 文件夹所在的路径。
完成此步骤后,IDE将自动继续设置所需的库并安装。然后,您可以继续创建新应用程序并开始制作基于MVC的Java应用程序。
创建应用程序
源代码与我的IDE相关,您的可能不同。
下一步是创建应用程序。根据您的IDE,创建一个新的应用程序;一个简单的基于Java的应用程序。
您应该注意一件事,与C#不同,在Java中,您的类名和包含该类的文件名必须匹配才能使程序运行。如果它们不匹配,Java会抱怨说该类必须存在于其自己的文件中。因此,如果您想遵循本文,您应该像我一样命名您的应用程序文件(我将提及包和文件的名称以及它们包含的代码),或者您可以创建自己的项目,然后编辑类和/或包的名称。
当您创建应用程序时,在Eclipse中,它是一个空项目,而在NetBeans中,它会创建一个包(与应用程序同名),并创建一个包含`Main`函数的类。在我的示例中,我将项目命名为`JavaHelloCollections`。如果您想遵循本文,请按原样命名,否则只需遵循“应用程序中的第一个包”的概念。此包中的类文件(取决于您的IDE)将位于包下,打开它。
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javahellocollections;
/**
*
* @author AfzaalAhmad
*/
public class JavaHelloCollections {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
}
}
这是一个非常基本的应用程序,它根本什么都**没做,只是编译和运行**。到目前为止,应用程序已经创建,但缺少MVC编程模式。那个阶段在此之后。因此,要创建应用程序的业务逻辑,我们实际上不会编辑此文件,我们将定义应用程序的MVC模式,然后我们将使用该模式确保用户与视图交互,视图与控制器交互,控制器在调用模型后从模型提供数据。
实现MVC模式
到目前为止,我们已经设置了环境,创建了可以运行的应用程序。现在是时候在我们的应用程序中实现MVC模式,并确保应用程序遵循规则了。
在 Java 中,我们创建包,就像我们在 C#、C++ 或其他面向对象编程语言中创建命名空间一样。包允许我们收集相似的类,或者按相同顺序或出于相同原因所需的类。在我们的应用程序中,我们需要创建一个 MVC 模式,为此我们可以创建三个不同的包,一个用于模型,一个用于视图,一个用于控制器。之后,我们可以将所有模型、视图和控制器添加到这些包中,并在需要时在不同的包中使用它们。
这样,我们可以将所有三个部分相互分离,但我们仍然可以在我们的部分中调用它们;通过导入包。这样,模型将留给控制器使用,视图应该调用控制器来获取或更新数据。
在本文中,我将使用文件示例来读写数据到文件。您可以使用自己的数据源;数据库、网络资源等。
既然我们首先要开发应用程序,然后通过运行应用程序来观察变化。那么实际上就没有必要遵循先创建视图,然后创建控制器来渲染视图,然后再创建模型来添加一些数据。我们可以从创建任何部分开始,然后将它们合并到一个应用程序中,然后运行它。
创建模型
让我们从为应用程序创建模型开始。该模型将为我们的应用程序提供数据。您应该考虑的一件事是,模型不仅仅是一个定义应用程序中数据结构的类,就像我们在数据库应用程序中所做的那样。结构必须在那里定义,在简单的应用程序中没有必要。这种模糊性通常由.NET框架上的Entity框架定义和创建,您在那里为数据库表的结构定义一个类,然后从数据库中填充该类的对象集合。模型是包含您数据的部分。它可以为您提供数据,并且可以更新数据;甚至*控制器调用模型来更新自身*,这意味着控制器将数据发送到模型,然后模型更新磁盘上的数据。
首先,创建一个新的包,记住要在同一个项目下创建一个新包,而不是在同一个包下。这将是同一个项目的两个不同包,我们将在应用程序中按需使用它们。将此包命名为`JavaMVCModels`。完成后,在其中创建一个新的类文件。此文件将作为应用程序的模型。将其命名为`HelloWorldModel`。打开文件,并修改文件。我们的场景是:
- 允许用户从数据源(如文件)加载数据
- 允许用户更新文件中的数据
在类中,编写以下代码:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package JavaMVCModels;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
*
* @author AfzaalAhmad
*/
public class HelloWorldModel {
public String getData() throws FileNotFoundException, IOException {
if(!(new File("F:\\file.txt").isFile())) {
// Create -- Make sure file exists -- the file before continuing
Files.createFile(Paths.get("F:\\file.txt"));
}
String data;
// We will be using a try-with-resource block
try (BufferedReader reader = new BufferedReader(
new FileReader("F:\\file.txt"))) {
// Access the data from the file
// Create a new StringBuilder
StringBuilder string = new StringBuilder();
// Read line-by-line
String line = reader.readLine();
string.append("<html>");
// While there comes a new line, execute this
while(line != null) {
// Add these lines to the String builder
string.append(line);
string.append("<br />");
// Read the next line
line = reader.readLine();
}
string.append("</html>");
data = string.toString();
} catch (Exception er) {
// Since there was an error, you probably want to notify the user
// For that error. So return the error.
data = er.getMessage();
}
// Return the string read from the file
return data;
}
public boolean writeData(String data) throws IOException, FileNotFoundException
{
// Save the data to the File
try (BufferedWriter writer = new BufferedWriter(
new FileWriter("F:\\file.txt"))) {
// Write the data to the File
writer.write(data);
// Return indicating the data was written
return true;
} catch (Exception er) {
return false;
}
}
}
上面的代码可以用以下几个阶段解释:
- 首先是声明此类的包。`JavaMVCModels`是包含类文件的包。
- 类名和文件名相似。
- 该类包含两个方法,一个用于提取数据,一个用于保存来自用户的数据。
上述代码使用了 Java 语言的文件 API。您可以在 Java 文档中找到 `File`、`BufferedWriter`、`BufferedReader` 等类,我无需解释它们。它们用于将数据存储到文件中,或从文件中提取数据。
在 Java SE 7 中,您可以利用一种新功能 try-with-resources 块,它会自动清理和释放资源。这里使用的就是类似的功能,否则我将不得不使用 `finally` 块手动调用 `.close()` 函数。这在 Java 文档中得到了很好的描述。
模型不需要与视图或控制器交互,相反,控制器将触发模型的函数,这就是为什么我们不会编写任何其他代码,除了获取/设置应用程序数据之外的任何代码。这正是为什么我在此类中不导入任何其他包(除了用于数据访问的Java IO API)的原因,否则在其他类中,您会看到我将整体导入其他类和包。
创建视图 - 使用NetBeans
注意:如果您使用的是Eclipse IDE,那么您可以简单地编写我的视图中的代码,Eclipse不像NetBeans那样支持Swing GUI的拖放功能。
现在到了应用程序的视图部分。应考虑类似的过程。将创建一个名为`JavaMVCViews`的新包,并为`HelloWorldView`创建一个类。但方式略有不同。您应该首先创建包。创建后,创建一个新的Swing `JFrame`表单。填写详细信息,然后继续。在我的示例中,名称是`HelloWorldView`。
NetBeans允许开发人员使用工具箱,通过拖放控件到窗口框来创建应用程序的GUI。您可以使用相同的方法,创建一个简单的GUI,如下所示。
这是我们应用程序的视图,包含足够的控件,使我们的应用程序能够**正常工作**。视图的工作只是显示控制器允许它显示的内容。此视图包含一些控件,控制器**应该能够与之交互**以随意显示或隐藏它们。
对于开发人员,以下是您可以在应用程序中编写的代码,以创建类似的视图。
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package JavaMVCViews;
// Call the import
import JavaMVCControllers.*;
/**
*
* @author AfzaalAhmad
*/
public class HelloWorldView extends javax.swing.JFrame {
// Create the class for the Controller
private HelloWorldController controller = new HelloWorldController();
/**
* Creates new form HelloWorldView
*/
public HelloWorldView() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
myLabel = new javax.swing.JLabel();
loadData = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
myMessage = new javax.swing.JTextArea();
writeData = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
setName("myFrame"); // NOI18N
myLabel.setText("Ok, the text is currently not loaded...");
loadData.setText("Load Data");
loadData.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
loadDataMouseClicked(evt);
}
});
myMessage.setColumns(20);
myMessage.setRows(5);
jScrollPane1.setViewportView(myMessage);
writeData.setText("Write Data");
writeData.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
writeDataMouseClicked(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(myLabel, javax.swing.GroupLayout.DEFAULT_SIZE,
380, Short.MAX_VALUE)
.addComponent(jScrollPane1))
.addContainerGap())
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(loadData)
.addGap(158, 158, 158))))
.addGroup(layout.createSequentialGroup()
.addGap(154, 154, 154)
.addComponent(writeData)
.addGap(0, 0, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(myLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(loadData)
.addGap(39, 39, 39)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(writeData)
.addContainerGap(82, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void loadDataMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
try {
String data = controller.getMessage();
myLabel.setText(data);
myLabel.setVisible(true);
} catch (Exception er) {
}
}
private void writeDataMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
String message = myMessage.getText();
controller.writeMessage(message);
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info :
javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(HelloWorldView.class.getName()).log
(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(HelloWorldView.class.getName()).log
(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(HelloWorldView.class.getName()).log
(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(HelloWorldView.class.getName()).log
(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new HelloWorldView().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JButton loadData;
public javax.swing.JLabel myLabel;
private javax.swing.JTextArea myMessage;
private javax.swing.JButton writeData;
// End of variables declaration
}
上面的代码用于创建视图。在NetBeans中,IDE隐藏了所有模糊的代码,只显示了所需的代码。在Eclipse中,您需要自己编写所有代码。因此,您可以在Eclipse中使用此代码来构建GUI。
上面的代码是拖放操作的结果。我**没有**编写除了**函数调用**之外的任何东西。
创建控制器
控制器是我们应用程序中至关重要的部分。它包含后端代码和逻辑,用于将应用程序的视图(间接是用户;因为用户将使用视图与应用程序交互)与模型(应用程序的数据源)连接起来。
应重复类似的过程,创建一个新包,命名为 `JavaMVCControllers`,创建一个新类并将其命名为 `HelloWorldController`。该类将控制我们应用程序的所有逻辑,因此至关重要的是,该应用程序具有足够的函数和灵活性来处理我们应用程序的所有事件和要求。例如,无论视图何时需要做某事,控制器都必须定义一个要触发的函数,模型也一样,将数据从模型加载到视图中,或者将数据从视图加载到模型中;让模型将数据保存到磁盘中。
类文件生成后,写入以下代码:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package JavaMVCControllers;
import JavaMVCViews.*;
import JavaMVCModels.*;
/**
*
* @author AfzaalAhmad
*/
public class HelloWorldController {
public void startApplication() {
// View the application's GUI
HelloWorldView view = new HelloWorldView();
view.setVisible(true);
}
public String getMessage() {
try {
HelloWorldModel model = new HelloWorldModel();
return model.getData();
} catch (Exception er) {
return "There was an error.";
}
}
public boolean writeMessage(String message) {
try {
HelloWorldModel model = new HelloWorldModel();
return model.writeData(message);
} catch (Exception er) {
return false;
}
}
}
这里的控制器访问我们应用程序中的视图包和模型包。它包含三个方法,其中一个是`startApplication`,它通过调用视图并将其设置为可见来启动应用程序的GUI。
另外两个函数只是将数据写入模型,或者从模型中提取数据并将其返回给视图。主要函数是`startApplication`函数。我们将调用此函数来实际启动应用程序。为什么它如此重要?在Java的Swing API中,一旦`JFrame`的`setVisible`属性设置为`true`,它就会变为可见。这就是为什么在此函数内部,GUI是可见的,并且应用程序现在看起来刚刚启动。它可以被认为是我们的MVC应用程序在我们的HelloJavaCollections项目中的入口点。
处理视图中的事件
视图中有一个我留到稍后完成的步骤,现在是时候了。在Swing中,您可以处理事件,例如鼠标、键盘或其他对控件的调用。在我们的应用程序中,我们只对鼠标事件感兴趣,以处理按钮上的鼠标点击事件。
在NetBeans中,您可以在按钮上右键单击(在GUI构建器中),然后在“事件”下的“鼠标”中单击“`mouseClick`”事件。
GUI构建器将自动添加代码来处理事件,并允许您编写在触发后执行的代码。例如,在我们的代码中,一旦触发被处理;用于处理它的事件被创建,GUI构建器会将您带到源代码面板,并允许您在事件下编写代码。我们应用程序中的两个事件是:
private void loadDataMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
try {
String data = controller.getMessage();
myLabel.setText(data);
myLabel.setVisible(true);
} catch (Exception er) {
}
}
private void writeDataMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
String message = myMessage.getText();
controller.writeMessage(message);
}
这些事件将在用户点击按钮时执行;具体取决于他点击了哪个按钮。
深入探讨,更多解释
现在代码已设置。应用程序现在已准备好运行,并按照我们希望的方式工作。控制器正在运行并将运行视图以渲染应用程序的GUI,用户可以交互以加载数据或更新文件中作为数据源的数据。
现在,让我们看看应用程序如何运行,首先调用哪些函数,以及MVC模式在我们的“Hello World”小应用程序中如何工作。从第一阶段开始,一直到应用程序的最后阶段……
运行应用程序
当您运行应用程序时,默认情况下(如果您没有更改行为),默认入口点设置为 `JavaHelloCollections` 类的 `Main` 函数。文章顶部的源代码就是我所说的。如果您运行应用程序,它不会显示任何内容,因为该函数是空的,它会什么都不做就终止。因此,更改应用程序并引入我们应用程序的 MVC 模式。像这样:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javahellocollections;
import JavaMVCControllers.*;
/**
*
* @author AfzaalAhmad
*/
public class JavaHelloCollections {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
HelloWorldController controller = new HelloWorldController();
// Start the application
controller.startApplication();
}
}
我所做的只是添加了控制器并触发了其中的`startApplication`函数。现在,一旦执行,应用程序将运行;*GUI将可见*。
在 startApplication 下
现在让我们看看当`startApplication`被触发时发生了什么。一旦`startApplication`被触发,控制权就转移到了控制器;控制器现在控制着应用程序,所有触发都必须通过控制器进行,视图和模型现在都依赖于控制器。让这三者都交互并不是一个好方法,它会扼杀MVC模式的主要目的。在`Controller`内部,函数是这样的:
public void startApplication() {
// View the application's GUI
HelloWorldView view = new HelloWorldView();
view.setVisible(true);
}
视图已加载
到目前为止,控制权仍在控制器手中,但并非直接。直接看来,控制权似乎在使用应用程序的用户手中。因为在用户要求应用程序执行某些操作(例如关闭应用程序、加载数据或保存数据等)之前,不会执行任何其他代码。一旦他发出命令,控制器将再次行动并执行操作,将控制权返回到用户手中。
这个方法一直持续到用户自己与视图交互。现在,让我们运行我们的应用程序,看看它会向我们展示什么。
请注意,NetBeans 设置的默认外观是 Nimbus,我没有费心去编辑它。
既然视图已加载,我们来稍微玩弄一下。好不好?:)
加载/写入数据
现在用户点击了加载数据按钮,该按钮连接到一个处理点击事件的事件。在该事件中,我们将调用控制器,向我们提供一些数据。我们将使用控制器中的数据加载到我们拥有的`JLabel`中;也就是显示“`Ok, the text is currently not loaded...`”的那个。
String data = controller.getMessage();
myLabel.setText(data);
myLabel.setVisible(true);
为了确保更改可见,您调用此函数重新创建视图并将其显示给用户。
我上面绘制的图片演示了当用户想要传输数据或接收数据时,控制器、视图和模型是如何交互的。我们假设第一个事件是加载数据,视图向控制器发出请求以提供数据。控制器然后向模型请求数据,如果数据被访问,则数据返回给视图,否则返回错误;错误可能是多种多样的,从未经授权的用户到磁盘错误。因此,返回何种数据取决于许多因素。
在 getMessage 内部
在 `getMessage` 函数内部,现在调用模型将数据加载到我们的流中。应用程序中的代码如下:
HelloWorldModel model = new HelloWorldModel();
return model.getData();
现在这将根据我上面绘制的相同流返回数据。数据将被控制器捕获,传递给视图进行渲染。让我们看看,在我们的代码中会发生什么;在我们的应用程序中,文件到目前为止不存在,因此创建后文件是空的,不会向用户显示任何内容。
现在让用户在文件中写入一些数据。然后,我们将再次处理相同的事件,但流量方向相反。这次,数据将不会通过控制器从数据源到视图。而是通过控制器从**视图到数据源**。
写入数据
现在,假设用户填入值并点击了*写入数据*按钮。会发生什么?控制器将再次启动,执行数据存储操作。您不应该将视图直接连接到数据源。
String message = myMessage.getText();
controller.writeMessage(message);
上面的代码很简单,它从文本字段获取数据,然后请求控制器将消息写入磁盘。让我们看看它内部发生了什么。
在 writeMessage 内部
在此函数内部,模型再次被调用,但方式相反。传递的数据然后存储在磁盘上;在该文件中。
HelloWorldModel model = new HelloWorldModel();
return model.writeData(message);
现在模型将根据模型类中指定的方法和逻辑存储数据。
我没有谈到模型中的方法,因为它们是关于Java语言本身和Java IO API的,与MVC模式无关。
一旦数据存储在文件中,您可以再次请求数据。再次遵循MVC连接,数据通过控制器从数据源一直传输到视图。视图在屏幕上渲染数据,然后显示数据。
数据回来后,里面有一些东西。所以Swing框架毫无问题地显示了它。
关注点
在本文中,您了解了软件开发的MVC框架(模式),以及如何在软件开发中实现此框架,将源代码分为三个不同的层。
- 模型 - 用于数据
- 视图 - 用于用户界面
- 控制器 - 用于后端代码
在Java中,您需要安装Java SDK,然后安装支持Java编程语言的IDE来开发应用程序。开发的应用程序可以使用任何编程架构。在我们的例子中,我们使用了MVC框架,还有其他一些,如MVVM。
在 Java 中,您将相似的类组合并合并到 *包* 中,就像在 C# 或 C++ 中创建命名空间一样。这些包有助于在不同名称下的不同包中分发相同类别的代码。
您可以在一个应用程序中创建任意数量的包,然后可以在项目中引用它们。同一项目中的类不需要导入其他类,但包外的类需要先引用您的包才能访问您的类。
在MVC模式中,用户无法直接访问数据,而是由控制器处理所有来自模型和发送到模型的请求,以证明数据的有效性和一致性。视图可以触发不同的命令,通过这些命令,我们可以强制应用程序执行操作。
在MVC中,您将源代码进行拆分,这样一旦应用程序达到企业级解决方案,您就不必因为代码现在看起来模糊而抓耳挠腮或拔头发。MVC允许您单独维护代码,一次只关注一个部分。无论是视图、模型还是控制器本身。您可以通过了解当前哪个部门需要您的关注,而将其他两个部门保持不变来更快地调试应用程序。
历史
- 本文的第一篇文章