一些疑问与这个 Swing MVC 实现有关。打开数据库连接应该是一个控制器任务?
Some doubts related this Swing MVC implementation. Opening a database connection should be a Controller task?
我正在学习与实施观察者模式(使用 Swing)相关的 Java 教程,但我有一些疑问。我的疑虑与观察者模式无关,而是与本教程应用程序的体系结构有关(基于类似 MVC 逻辑的东西)
因此它包含一个 Application class,其中包含作为应用程序入口点的 main() 方法:
public class Application {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
runApp();
}
});
}
public static void runApp() {
Model model = new Model();
View view = new View(model);
Controller controller = new Controller(view, model);
view.setLoginListener(controller);
}
}
正如你在这里看到的,它被声明为一个 Model 对象(用于数据),一个 Controller 对象,实际上只是执行与单击我视图中定义的按钮相关的操作,这是 View 代码:
public class Controller implements LoginListener {
private View view;
private Model model;
public Controller(View view, Model model) {
this.view = view;
this.model = model;
}
@Override
public void loginPerformed(LoginFormEvent event) {
System.out.println("Login event received: " + event.getName() + "; " + event.getPassword());
}
}
和 View 对象,它们使用 JButton okButton 实现登录表单(用户名和密码)(它的点击是从前一个 控制器 对象):
public class View extends JFrame implements ActionListener {
private Model model;
private JButton okButton;
private JTextField nameField;
private JPasswordField passField;
private JPasswordField repeatPassField;
private LoginListener loginListener;
public View(Model model) {
super("MVC Demo");
this.model = model;
nameField = new JTextField(10);
passField = new JPasswordField(10);
repeatPassField = new JPasswordField(10);
okButton = new JButton("Create user");
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.LAST_LINE_END;
gc.gridx = 1;
gc.gridy = 1;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(100, 0, 0, 10);
gc.fill = GridBagConstraints.NONE;
add(new JLabel("Name: "), gc);
gc.anchor = GridBagConstraints.LAST_LINE_START;
gc.gridx = 2;
gc.gridy = 1;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(100, 0, 0, 0);
gc.fill = GridBagConstraints.NONE;
add(nameField, gc);
gc.anchor = GridBagConstraints.LINE_END;
gc.gridx = 1;
gc.gridy = 2;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(0, 0, 0, 10);
gc.fill = GridBagConstraints.NONE;
add(new JLabel("Password: "), gc);
gc.anchor = GridBagConstraints.LINE_START;
gc.gridx = 2;
gc.gridy = 2;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(0, 0, 0, 0);
gc.fill = GridBagConstraints.NONE;
add(passField, gc);
gc.anchor = GridBagConstraints.LINE_END;
gc.gridx = 1;
gc.gridy = 3;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(0, 0, 0, 10);
gc.fill = GridBagConstraints.NONE;
add(new JLabel("Repeat password: "), gc);
gc.anchor = GridBagConstraints.LINE_START;
gc.gridx = 2;
gc.gridy = 3;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(0, 0, 0, 0);
gc.fill = GridBagConstraints.NONE;
add(repeatPassField, gc);
gc.anchor = GridBagConstraints.FIRST_LINE_START;
gc.gridx = 2;
gc.gridy = 4;
gc.weightx = 1;
gc.weighty = 100;
gc.fill = GridBagConstraints.NONE;
add(okButton, gc);
okButton.addActionListener(this);
// Database db = new Database();
// Database db = Database.getInstance();
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
try {
Database.getInstance().connect();
} catch (Exception e1) {
JOptionPane.showMessageDialog(View.this, "Unable to connect to database.",
"Error", JOptionPane.WARNING_MESSAGE);
e1.printStackTrace();
}
}
@Override
public void windowClosing(WindowEvent e) {
Database.getInstance().disconnect();
}
});
setSize(600, 500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
String password = new String(passField.getPassword());
String repeat = new String(repeatPassField.getPassword());
if (password.equals(repeat)) {
String name = nameField.getText();
fireLoginEvent(new LoginFormEvent(name, password));
} else {
JOptionPane.showMessageDialog(this, "Passwords do not match.",
"Error", JOptionPane.WARNING_MESSAGE);
}
}
public void setLoginListener(LoginListener loginListener) {
this.loginListener = loginListener;
}
public void fireLoginEvent(LoginFormEvent event) {
if (loginListener != null) {
loginListener.loginPerformed(event);
}
}
}
它似乎遵循 classic MVC 逻辑,但如果您查看 View class,您会发现以下代码:
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
try {
Database.getInstance().connect();
} catch (Exception e1) {
JOptionPane.showMessageDialog(View.this, "Unable to connect to database.",
"Error", JOptionPane.WARNING_MESSAGE);
e1.printStackTrace();
}
}
@Override
public void windowClosing(WindowEvent e) {
Database.getInstance().disconnect();
}
});
我不太喜欢 Swing,我也不完全知道 WindowAdapter 对象是什么(它是什么?)但在我看来,这段代码中添加了处理与主要 windows 开幕相关的事件的侦听器。
因此,当我的应用程序的主要 window 打开时,View 获取到数据库的新连接,当它关闭时,连接被关闭。
我的疑问是:但这是反模式吗?打开与数据库的连接不是 Controller?
的责任
Tnx
因此,MVC 实际上并未明确解决持久性问题。这里确实有两种思想流派。将其烘焙到模型中,使模型变为"self persisting"。或者在控制器中进行。
在视图层打开它是绝对不能接受的做法。这里肯定有view/controller逻辑的混合。
我正在学习与实施观察者模式(使用 Swing)相关的 Java 教程,但我有一些疑问。我的疑虑与观察者模式无关,而是与本教程应用程序的体系结构有关(基于类似 MVC 逻辑的东西)
因此它包含一个 Application class,其中包含作为应用程序入口点的 main() 方法:
public class Application {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
runApp();
}
});
}
public static void runApp() {
Model model = new Model();
View view = new View(model);
Controller controller = new Controller(view, model);
view.setLoginListener(controller);
}
}
正如你在这里看到的,它被声明为一个 Model 对象(用于数据),一个 Controller 对象,实际上只是执行与单击我视图中定义的按钮相关的操作,这是 View 代码:
public class Controller implements LoginListener {
private View view;
private Model model;
public Controller(View view, Model model) {
this.view = view;
this.model = model;
}
@Override
public void loginPerformed(LoginFormEvent event) {
System.out.println("Login event received: " + event.getName() + "; " + event.getPassword());
}
}
和 View 对象,它们使用 JButton okButton 实现登录表单(用户名和密码)(它的点击是从前一个 控制器 对象):
public class View extends JFrame implements ActionListener {
private Model model;
private JButton okButton;
private JTextField nameField;
private JPasswordField passField;
private JPasswordField repeatPassField;
private LoginListener loginListener;
public View(Model model) {
super("MVC Demo");
this.model = model;
nameField = new JTextField(10);
passField = new JPasswordField(10);
repeatPassField = new JPasswordField(10);
okButton = new JButton("Create user");
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.LAST_LINE_END;
gc.gridx = 1;
gc.gridy = 1;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(100, 0, 0, 10);
gc.fill = GridBagConstraints.NONE;
add(new JLabel("Name: "), gc);
gc.anchor = GridBagConstraints.LAST_LINE_START;
gc.gridx = 2;
gc.gridy = 1;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(100, 0, 0, 0);
gc.fill = GridBagConstraints.NONE;
add(nameField, gc);
gc.anchor = GridBagConstraints.LINE_END;
gc.gridx = 1;
gc.gridy = 2;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(0, 0, 0, 10);
gc.fill = GridBagConstraints.NONE;
add(new JLabel("Password: "), gc);
gc.anchor = GridBagConstraints.LINE_START;
gc.gridx = 2;
gc.gridy = 2;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(0, 0, 0, 0);
gc.fill = GridBagConstraints.NONE;
add(passField, gc);
gc.anchor = GridBagConstraints.LINE_END;
gc.gridx = 1;
gc.gridy = 3;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(0, 0, 0, 10);
gc.fill = GridBagConstraints.NONE;
add(new JLabel("Repeat password: "), gc);
gc.anchor = GridBagConstraints.LINE_START;
gc.gridx = 2;
gc.gridy = 3;
gc.weightx = 1;
gc.weighty = 1;
gc.insets = new Insets(0, 0, 0, 0);
gc.fill = GridBagConstraints.NONE;
add(repeatPassField, gc);
gc.anchor = GridBagConstraints.FIRST_LINE_START;
gc.gridx = 2;
gc.gridy = 4;
gc.weightx = 1;
gc.weighty = 100;
gc.fill = GridBagConstraints.NONE;
add(okButton, gc);
okButton.addActionListener(this);
// Database db = new Database();
// Database db = Database.getInstance();
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
try {
Database.getInstance().connect();
} catch (Exception e1) {
JOptionPane.showMessageDialog(View.this, "Unable to connect to database.",
"Error", JOptionPane.WARNING_MESSAGE);
e1.printStackTrace();
}
}
@Override
public void windowClosing(WindowEvent e) {
Database.getInstance().disconnect();
}
});
setSize(600, 500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
String password = new String(passField.getPassword());
String repeat = new String(repeatPassField.getPassword());
if (password.equals(repeat)) {
String name = nameField.getText();
fireLoginEvent(new LoginFormEvent(name, password));
} else {
JOptionPane.showMessageDialog(this, "Passwords do not match.",
"Error", JOptionPane.WARNING_MESSAGE);
}
}
public void setLoginListener(LoginListener loginListener) {
this.loginListener = loginListener;
}
public void fireLoginEvent(LoginFormEvent event) {
if (loginListener != null) {
loginListener.loginPerformed(event);
}
}
}
它似乎遵循 classic MVC 逻辑,但如果您查看 View class,您会发现以下代码:
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
try {
Database.getInstance().connect();
} catch (Exception e1) {
JOptionPane.showMessageDialog(View.this, "Unable to connect to database.",
"Error", JOptionPane.WARNING_MESSAGE);
e1.printStackTrace();
}
}
@Override
public void windowClosing(WindowEvent e) {
Database.getInstance().disconnect();
}
});
我不太喜欢 Swing,我也不完全知道 WindowAdapter 对象是什么(它是什么?)但在我看来,这段代码中添加了处理与主要 windows 开幕相关的事件的侦听器。
因此,当我的应用程序的主要 window 打开时,View 获取到数据库的新连接,当它关闭时,连接被关闭。
我的疑问是:但这是反模式吗?打开与数据库的连接不是 Controller?
的责任Tnx
因此,MVC 实际上并未明确解决持久性问题。这里确实有两种思想流派。将其烘焙到模型中,使模型变为"self persisting"。或者在控制器中进行。
在视图层打开它是绝对不能接受的做法。这里肯定有view/controller逻辑的混合。