一些疑问与这个 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逻辑的混合。