扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
都详细过了一遍了,而我们都知道MVC是一种比较特殊的模式,MVC并不属于GOF的23个设计模式之列,但是Smalltalk的MVC框架结构在著名的GOF书中作为一个重要的例子被提出来,并给予了很高的评价。一般的来讲,我们认为GOF的23个模式是一些中级的模式,在它下面还可以抽象出一些更为一般的低层的模式,在其上也可以通过组合来得到一些高级的模式,即架构模式。MVC就可以看作是一些模式进行组合之后的结果(实际上,MVC的出现要早于设计模式的提出,因而只是对它在设计模式的基础上进行在分析)。所以说现在有必要站在设计模式的思想上来看MVC模式。<<Java与模式>>在MVC模式与用户输入数据检查这个专题里大量地谈到MVC模式跟设计模式的关系,本文按这个专题的思路以笔记的形式展开。
MVC模式可以分解为以下设计模式
在GOF书的 Introduction中,有一小节是“Design Patterns in Smalltalk MVC”即介绍在MVC模式里用到的设计模式。它大概向我们传达了这样的信息:合成模式+策略模式+观察者模式约等于MVC模式(当然MVC模式要多一些东西)。也就是说它在大部分情况下是下面几个模式:
(转载开始)
Model的设计
一个按钮的model所应该具备的行为由一个接口ButtonModel来完成。一个按钮model实例封装了其内部的状态,并且定义了按钮的行为。它的所有方法可以分为四类:
1、查询内部状态
2、操作内部状态
3、添加和删除事件监听器
4、发生事件
程序员通常并不会直接和model以及view/controller打交道,他们通常隐藏于那些继承自java.awt.Component的组件里面了,这些组件就像胶水一样把MVC三者合三为一。也正是由于这些继承的组件对象,一个程序员可以很方便的混合使用Swing组件和AWT组件,然后,我们知道,Swing组件有很多都是直接继承自相应的AWT组件,它能提供比AWT组件更加方便易用的功能,所以通常情况下,我们没有必要混合使用两者。
1. /**
2.
3. * Sets the model that this button represents.
4.
5. * @param m the new <code>ButtonModel</code>
6.
7. * @see #getModel
8.
9. * @beaninfo
10.
11. * bound: true
12.
13. * description: Model that the Button uses.
14.
15. */
16.
17. public void setModel(ButtonModel newModel) {
18.
19.
20.
21. ButtonModel oldModel = getModel();
22.
23.
24.
25. if (oldModel != null) {
26.
27. oldModel.removeChangeListener(changeListener);
28.
29. oldModel.removeActionListener(actionListener);
30.
31. changeListener = null;
32.
33. actionListener = null;
34.
35. }
36.
37.
38.
39. model = newModel;
40.
41.
42.
43. if (newModel != null) {
44.
45. changeListener = createChangeListener();
46.
47. actionListener = createActionListener();
48.
49. itemListener = createItemListener();
50.
51. newModel.addChangeListener(changeListener);
52.
53. newModel.addActionListener(actionListener);
54.
55. newModel.addItemListener(itemListener);
56.
57. mnemonic = newModel.getMnemonic();
58.
59. } else {
60.
61. mnemonic = '\0';
62.
63. }
64.
65.
66.
67. updateDisplayedMnemonicIndex(getText(), mnemonic);
68.
69.
70.
71. firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel);
72.
73. if (newModel != oldModel) {
74.
75. revalidate();
76.
77. repaint();
78.
79. }
80.
81. }
注:你可以多花一些时间按我上面提供的链接地址来仔细阅读一下Button类及其它相关类的源代码。
ButtonModel类
ButtonModel维护着三种类型的状态信息:是否被按下(pressed),是否“武装上了”(armed),是否被选择(selected)。它们都是boolean类型的值。
一些按钮还可能被选择(selected),这种状态通过重复的点击按钮取得true或者false的值。
注:查看ButtonModel源代码我们可以看到它是一个接口,定义了一组方法:
public interface ButtonModel extends ItemSelectable {
boolean isArmed();
boolean isPressed();
…
boolean isRollover();
void addActionListener(ActionListener l);
void removeActionListener(ActionListener l);
void addItemListener(ItemListener l);
…
void removeChangeListener(ChangeListener l);
其实看到这里,如果你再回头看下这个例子刚开始时“Model的设计”以及前面的内容,就会明白什么是“Mod封装的是数据源和所有基于对这些数据的操作。在一个组件中,Model往往表示组件的状态和操作这些状态的方法,往往是一系列的公开方法。通过这些公开方法,便可以取得模型端的所有功能”
我们再来看看AbstractButton的源代码:
1. public abstract class implements ItemSelectable, SwingConstants { AbstractButton extends JComponent
2. protected ButtonModel model= null;
3. protected ChangeListener changeListener = null;
4. protected ActionListener actionListener = null;
5. protected ItemListener itemListener = null;
6. protected transient ChangeEvent changeEvent;
7. public boolean isSelected() {
8. return model.isSelected();
9. }
10.public void doClick() {
11.doClick(68);
12. }
13.public void doClick(int pressTime) {
14. Dimension size = getSize();
15.model.setArmed(true);
16. model.setPressed(true);
17. paintImmediately(new Rectangle(0,0, size.width, size.height));
18.try {
19.Thread.currentThread().sleep(pressTime);
20. } catch(InterruptedException ie) {
21.}
22.model.setPressed(false);
23.model.setArmed(false);
24.}
25.//其它代码
26.}
上面的代码setArmed等方法是由DefaultButtonModel定义的,它是ButtonModel接口的一个默认实现。我们如果继承了DefaultButtonModel,这样可以覆盖缺省的状态定义,实现有个性的按钮。
ButtonUI类按钮的view/controller是负责构建表示层的。缺省情况下它仅仅是用背景色画一个矩形而已,他们的子类继承了他们并且覆盖了绘制的方法,使得按钮可以有许多不同的表现,例如MOTIF,Windows 95,Java样式等等。
注:在javax.swing.plaf这个包里我们可以找到ButtonUI,这是一个抽象类,类内部是空的,而在javax.swing.plaf.basic这个包里我们可以找到BasicButtonUI,它继承自ButtonUI,其实我们观察下包结构会发现有javax.swing.plaf.metal,javax.swing.plaf.multi等,这几个就是来控制Button在不同系统间的不同的显示效果。:
public void update(Button button, Graphics graphics)
{
}
public void paint(Button button, Graphics graphics)
{
Dimension dimension = button.getSize();
Color color = button.getBackground();
graphics.setColor(color);
graphics.fillRect(0, 0, dimension.width, dimension.height);
}
ButtonUI类并不自己处理AWT事件,他们会使用一个定制的事件监听器把低级的AWT事件翻译为高级的Button模型期望的语义事件。下面就是安装/卸载事件监听器的代码。
private static ButtonUIListener buttonuilistener = null;
public void uninstallUI(Button button)
{
button.removeMouseListener(buttonuilistener);
button.removeMouseMotionListener(buttonuilistener);
button.removeChangeListener(buttonuilistener);
}
View/Controller实际上就是一些方法。他们不维护任何自己的状态信息。因此,许多按钮的实例可以共享一个ButtonUI实例。ButtonUI是通过在方便的参数列表里面加上按钮的引用来区分各个不同的按钮。
ButtonUIListener类
ButtonUIListener类可以帮助Button类去转变鼠标或者键盘的输入为对按钮模型的操作。这个监听器类实现了:MouseListener,MouseMotionListener,ChangeListener接口,并且处理一下事件:
public void mouseDragged(MouseEvent mouseevent)
{
Button button = (Button)mouseevent.getSource();
ButtonModel buttonmodel = button.getModel();
if (buttonmodel.isPressed())
{
if (button.getUI().contains(button, mouseevent.getPoint()))
{
buttonmodel.setArmed(true);
}
else
{
buttonmodel.setArmed(false);
}
}
}
public void mousePressed(MouseEvent mouseevent)
{
Button button = (Button)mouseevent.getSource();
ButtonModel buttonmodel = button.getModel();
buttonmodel.setPressed(true);
buttonmodel.setArmed(true);
}
public void mouseReleased(MouseEvent mouseevent)
{
Button button = (Button)mouseevent.getSource();
ButtonModel buttonmodel = button.getModel();
buttonmodel.setPressed(false);
buttonmodel.setArmed(false);
}
public void stateChanged(ChangeEvent changeevent)
{
Button button = (Button)changeevent.getSource();
button.repaint();
}
(转载完)
通过这些相信大家能够感受到Swing的设计是MVC的典范,这是一点都不假的。下一节将要看看在基于B/S的应用中MVC模式是如何被应用的。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。