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

来源:互联网 发布:视频php服务器配置 编辑:程序博客网 时间:2024/04/29 13:10

有很多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的观察者模式,顿时恍然大悟,有时候,多多想想这些东西对巩固基础知识还是很有好处的。。

原创粉丝点击