【发布时间】:2015-08-22 16:37:43
【问题描述】:
我正在研究用 Java 实现的观察者模式,我对教程实现的具体工作原理有些疑问。
我知道这种模式用于所有期望用户与 GUI 交互的情况(例如用户单击按钮)或事件在不可预测的时间发生的所有情况(如计时器、当计时器捕捉到一个事件时,必须处理)。
我知道在观察者模式中涉及两种不同类型的对象:
主题对象:即在不可预知的时间发生某事的对象(例如,可以随时单击的按钮用户)
observer 对象(或 listener):在我看来,它包含了当某些东西变为 subject 对象(例如它处理我的按钮的点击)。这是真的还是我错过了什么?我对这种说法绝对不正确...我怀疑 observer 对象可能只需要监听 subject 的变化并对主题执行操作当这种变化发生时。例如:按钮(subject)被点击,观察者监听它并发现这个变化并对主题执行特定的操作(对主题对象执行特定的方法)。 p>
正确的解释是什么?观察者监听主体变化并执行观察者定义的操作还是执行主体定义的操作?
我知道要做到这一点,我可以将 subject 的引用传递给 observer(我认为执行的操作已定义到主题中。)但这是一种不好的做法,因为它涉及主体和观察者之间的一种紧密耦合。我知道存在界面驱动的解决方案,但我很难弄清楚。
本教程制作了一个表示使用 Swing 呈现 2 个按钮的视图的示例:
package com.caveofprogramming.designpatterns.demo1.view;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import com.caveofprogramming.designpatterns.demo1.model.Model;
public class View extends JFrame implements ActionListener {
private Model model;
private JButton helloButton; // SUBJECT OBJECT: l'oggetto su cui avviene l'evento
private JButton goodbyeButton; // SUBJECT OBJECT: l'oggetto su cui avviene l'evento
public View(Model model) {
super("MVC Demo");
this.model = model;
// Crea i 2 bottoni definiti sopra:
helloButton = new JButton("Hello!");
goodbyeButton = new JButton("Goodbye!");
// Setta il layout manager da usare che stabilisce come sono posizionati gli elementi:
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.CENTER;
gc.gridx=1;
gc.gridy=1;
gc.weightx=1;
gc.weighty=1;
gc.fill=GridBagConstraints.NONE;
add(helloButton, gc); // Aggiunge helloButton dentro il layout
gc.anchor = GridBagConstraints.CENTER;
gc.gridx=1;
gc.gridy=2;
gc.weightx=1;
gc.weighty=1;
gc.fill=GridBagConstraints.NONE;
add(goodbyeButton, gc); // Aggiunge goodbyeButton dentro il layout
helloButton.addActionListener(this);
goodbyeButton.addActionListener(this);
goodbyeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Sorry to see you go.");
}
});
setSize(600, 500); // Setta le dimensioni della finestra
setDefaultCloseOperation(EXIT_ON_CLOSE); // Setta il comportamento di cosa succede premendo il tasto X
setVisible(true); // Setta la finestra come visibile
}
@Override
public void actionPerformed(ActionEvent e) {
JButton source = (JButton)e.getSource();
if(source == helloButton) {
System.out.println("Hello there!");
}
else {
System.out.println("Some other button.");
}
}
}
在这个例子中,我有 2 个按钮代表我的 subject 对象,它们是:
private JButton helloButton;
private JButton goodbyeButton;
View类实现了一个ActionListener接口(是不是前面提到的接口?)
查看 ActionListener.class 我发现:
// Method descriptor #8 (Ljava/awt/event/ActionEvent;)V
public abstract void actionPerformed(java.awt.event.ActionEvent arg0);
这是一个必须实现的方法,这是一个动作发生时调用的方法,我必须实现它,这个:
@Override
public void actionPerformed(ActionEvent e) {
JButton source = (JButton)e.getSource();
if(source == helloButton) {
System.out.println("Hello there!");
}
else {
System.out.println("Some other button.");
}
}
actionPerformed() 方法在 View 类中实现,因为它扩展了 ActionListener 接口并处理按钮的点击。
ActionListener 接口实现是我的observer 对象吗?这意味着 View* 类包含 **subject 对象(我的按钮),但它也是 observer/listener 实现?
要将 listerner(observer 对象)添加到按钮上:
helloButton.addActionListener(this);
我通过 this 因为包含 observer 的类与定义 subject 对象的类相同。对吗?
这是一个最佳实践,因为我将主体和观察者捆绑到一个类中,并且我没有通过观察者内部的主体引用派生的紧密耦合?
这是我的推理正确还是我遗漏了什么?
【问题讨论】:
-
我已经看到这种模式被多次使用,而且几乎总是以眼泪告终。 :)
-
检查,在侦听器中单击了哪个按钮是个坏主意。毕竟,您可以为两个按钮编写不同的侦听器以避免
if。这不是很多工作:在这种情况下,匿名类、lambda 表达式和方法引用是您的朋友。
标签: java swing jakarta-ee design-patterns observer-pattern