看JSlider的jdk源码学观察者模式

有很多Swing组建都是用MVC体系结构,其中Model层结合观察者模式通知所有观察该组件的对象。看JSlider类的部分源代码(其他的Swing组件有些是类似的):

public JSlider(int i, int j, int k, int l)    {
        changeListener = createChangeListener();
        sliderModel = new DefaultBoundedRangeModel(l, 0, j, k);
        sliderModel.addChangeListener(changeListener);
        updateUI();
         }
public JSlider(BoundedRangeModel boundedrangemodel)    {
        changeListener = createChangeListener();
        setModel(boundedrangemodel);
        sliderModel.addChangeListener(changeListener);
        updateUI();
    }

可以看到JSlider的构造方法有两种,一种指定长宽的,另一种指定Model的,所指定的model必须是 BoundedRangeModel接口的实现类,默认的Model为 DefaultBoundedRangeModelupdateUI方法和MVC结构有关,这里先不说,我们讨论观察者模式。

构造器先new一个DefaultBoundedRangeModel类型的model,然后为它添加观察者,这里就是changeListener对象了,该对象是通过 createChangeListener()创建出来的,我们看看这个方法:

protected ChangeListener createChangeListener()    {
        return new ModelListener();
    }

其中 ModelListener是JSlider的内部类:

private class ModelListener
        implements ChangeListener, Serializable    {
        public void stateChanged(ChangeEvent changeevent)        {
            fireStateChanged();
        }
        final JSlider this$0;
        private ModelListener()        {
            this$0 = JSlider.this;
            super();
        }
    }

ModelListener实现ChangeListener接口,任何实现了该接口的类都可以观察JSlider对象,通过上面的 addChangeListener()方法,这也是我们通常所说的监听器,这正类似于我们所熟悉的addActionListener()方法,只不过监听的对象变了,由按钮变成了滑块而已。我们再看看 addChangeListener的实现:

public void addChangeListener(ChangeListener changelistener)    {
        listenerList.add(javax/swing/event/ChangeListener, changelistener);
    }

原来JSlider内部维护一个 listenerList链表(EventListenerList listenerList其实是在父类JComponent中定义的),我们添加的观察者都被添加到了这个链表。当JSlider的model发生变化时,就会通知所有的观察者,那么是怎么观察的呢?这正是观察者模式的神奇之处。当JSlider的model发生变化时,会调用内部类 ModelListenerstateChanged()方法,从源代码可以看到,该方法调用 fireStateChanged():

protected void fireStateChanged()    {
        Object aobj[] = listenerList.getListenerList();
        for(int i = aobj.length - 2; i >= 0; i -= 2)        {
            if(aobj[i] != javax/swing/event/ChangeListener)
                continue;
            if(changeEvent == null)
                changeEvent = new ChangeEvent(this);
            ((ChangeListener)aobj[i + 1]).stateChanged(changeEvent);
        }
    }

该方法依次调用 listenerList链表中除了第0个的所有观察者的 stateChanged()方法,这样所有的观察者就都被通知到了。分析了这么多,是时候总结了:

观察者模式通常有4类参与者:

抽象主题(Subject):在这里就是BoundedRangeModel

抽象观察者(Observer):ChangeListener

具体主题(ConcreteSubject):DefaultBoundedRangeModel

具体观察者(ConcreteObserver):ModelListener

在抽象主题接口中,通常定义addXXXListener(),removeXXXListener(),notifyAllListener()等方法,具体主题实现该接口,并维护一个Listener链表以使每个观察者都能得到通知。在抽象观察者中,定义update()方法,被具体观察者实现,主题变化时,调用该方法。

见惯了addActionListener()这类方法,都习以为常了,便很少去想为什么。看完JSlider的观察者模式,顿时恍然大悟,有时候,多多想想这些东西对巩固基础知识还是很有好处的。。

你可能感兴趣的:(源码,swing,JavaSE)