MVC如何使用java swing GUI

假设我有一个带有textfeild和按钮的swing GUI。 当我单击按钮时,我想将该值保存在db中的文本中并返回joptionpane“success”消息。
我以前这样做的方式是
型号 :JDBC类
查看 :GUI:在该按钮的“ 动作执行 ”动作中,我使用参数调用save方法。

Controller con = new Controller(); con.save(text1.getText()); 

控制器 :编写保存方法。

  JDBC db = new public void save(jTextfeild text){ text= text1.getText(); boolean b= db.putData("insert into .. values(text)"); if(b){ JOptionPane("Success"); } } 

这就是我的开始。 但后来我明白这不应该是这样的,这是完全不安全和愚蠢的。
我真的想学习如何在MVC中正确地做到这一点。 请用一个小例子来解释这个问题。 感谢您的时间。

这是一个很难掌握的东西,比如Swing,它已经使用了一种MVCforms,虽然更像是VC-M,其中模型与视图和控制器分开,但视图和控制器组合在一起。

考虑一下JButton ,你不提供一个控制器来管理当用户按下一个键或用鼠标点击它时它是如何触发的,这是在内部完成的,并且会在发生时通知你。

考虑到这一点,您需要允许视图半自我管理。 例如,根据您的要求,视图将具有按钮和文本字段。

视图本身将管理用户与按钮本身之间的交互(例如,维护内部ActionListener ),但随后会向控制器提供有关控制器可能感兴趣的任何状态更改的通知。

在更纯粹的MVC意义上,视图和模型将不会彼此了解任何事情,控制器将管理它们。 这与Swing的工作方式有点矛盾,因为Swing允许您将模型直接传递给视图,只需查看任何Swing组件。

这并不意味着你不能让事情发挥作用,但你需要知道这个概念可能会动摇或需要“按摩”才能更好地发挥作用。

通常情况下,当我接近这些类型的东西时,我会退后一步,看看更广泛的画面。

  • 您有一个视图,可以接受文本并生成文本或更改它
  • 您有一个可以加载和修改文本的模型,但提供的其他事件很少
  • 您有一个控制器想要从模型中获取文本并将其提供给视图并监视视图对文本的更改并在模型中更新它们

现在,MVC在“代码到接口(不是实现)”的概念下工作得非常好,在这种程度上,我倾向于从合同开始……

查看合同……

 public interface TextView { public void setText(String text); public String getText(); public void addTextViewObserver(TextViewObserver observer); public void removeTextViewObserver(TextViewObserver observer); } public interface TextViewObserver { public void textWasChanged(TextView view); } 

现在,视图的一个要求是在文本以某种有意义的方式发生变化时生成事件,为此,我使用了一个简单的观察者模式来实现。 现在你可以说控制器是观察者,但在我看来,控制器可能具有我不想暴露给视图的function(例如模型)

示范合同……

接下来是模特……

 public interface TextModel { public String getText(); public void setText(String text); } 

非常简单。 现在,您可以考虑为这些方法添加某种Exception以允许模型因某种原因失败,但Exception应该像您可以做到的那样通用(甚至是自定义Exception ),以便您可以替换你应该需要实施

控制器合同……

最后,控制器……

 public interface TextViewController { public TextView getTextView(); public TextModel getTextModel(); } 

再次,非常简单。 您可能对控制器有更复杂的要求,但对于此示例,这是我们真正需要的。

实现…

视图…

 public class TextViewPane extends JPanel implements TextView { private JTextField textField; private JButton updateButton; private List observers; public TextViewPane() { observers = new ArrayList<>(25); textField = new JTextField(25); updateButton = new JButton("Update"); updateButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { fireTextWasChanged(); } }); setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; add(textField, gbc); add(updateButton, gbc); } @Override public void setText(String text) { textField.setText(text); } @Override public String getText() { return textField.getText(); } @Override public void addTextViewObserver(TextViewObserver observer) { observers.add(observer); } @Override public void removeTextViewObserver(TextViewObserver observer) { observers.remove(observer); } protected void fireTextWasChanged() { for (TextViewObserver observer : observers) { observer.textWasChanged(this); } } } 

模型…

 public class SimpleTextModel implements TextModel { private String text = "This is some text"; @Override public String getText() { return text; } @Override public void setText(String text) { this.text = text; } } 

控制器…

 public class SimpleTextController implements TextViewController, TextViewObserver { private TextView view; private TextModel model; public SimpleTextController(TextView view, TextModel model) { this.view = Objects.requireNonNull(view, "TextView can not null"); this.model = Objects.requireNonNull(model, "TextModel can not be null"); view.addTextViewObserver(this); } @Override public TextView getTextView() { return view; } @Override public TextModel getTextModel() { return model; } @Override public void textWasChanged(TextView view) { getTextModel().setText(view.getText()); } } 

把它放在一起…

 TextViewPane view = new TextViewPane(); TextModel model = new SimpleTextModel(); TextViewController controller = new SimpleTextController(view, model); JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(view); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); 

现在,所有这些只是一个可能解决方案的一个例子。 例如,您可以拥有一个控制器实现,该实现具有模型或视图的特定实现或两者。

关键是,你应该不在乎。 控制器不关心视图是如何实现的,它只关心它将生成textWasChanged事件。 该模型根本不关心视图(反之亦然),控制器不关心模型,只是它会得到并设置一些文本。

有关更复杂的示例,您可以查看Java和GUI – ActionListeners根据MVC模式属于哪里?

经过思考

  • 这只是解决问题的一种可能方式。 例如,您可以将视图限制为单个观察者。
  • 你应该总是在思考“我可以改变MVC的任何一部分并且它仍然可以工作吗?” 这使您可以考虑更改任何一部分实施可能对周围合同产生的问题。 你应该明白每个层的实现方式并不重要
  • 视图可以充当另一个子视图的控制器(或充当子视图的另一个控制器的容器)。 这有时会吓到人,但是视图可以作为一个或多个子控制器/视图的父容器,这允许您开发复杂的UI
  • 不要在合同中公开实现细节,例如,模型不应抛出SQLException ,因为另一个实现可能不基于基于SQL的解决方案。 不要暴露UI元素,这意味着所有实现都需要实现这些元素。 如果我想要一个向用户而​​不是JTextField呈现JComboBox的视图的实现会发生什么? 这也是我在视图合约中不使用ActionListener的原因,因为我不知道视图的实现如何实际生成textWasChanged事件