Previously on OOP:
In the last article, we have made an example of the way to write a login dialog with user name and dialog.
在GuiExample project中,还有几个非常日常的GUI的代码,比如含有“OK”和“Cancel”两个按钮的对话框,投票表决的对话框,等等。这些很多都是其他公司开发的、有版权的,我们需要用的时候可以直接引用,不必过于纠结是怎么实现的,所以本黄鸭在这里就不分析这些例子了。
在前文中,我们曾经讲到Interface有几种功能:以Comparable / Comparator / Iterable / Iterator为代表的、定义common behavior的功能;还有以Observable / Observer为代表的、实现communication decoupling的功能;等等。而且,我们已经举过很多Comparable / Comparator的例子,还有若干Iterable / Iterator的例子;所以在本文中,本黄鸭将要举一个Observable / Observer的例子,被分离的联系是在GUI的MVC之间的联系。
这一段代码无比纠结,本黄鸭也看不懂。
SwingUtilities应该是一个类的fully qualified name;invokeLater()函数是SwingUtilities类中的一个静态函数,它需要的参数是一个RunnableInterface的实例;RunnableInterface中也确实有一个run()函数需要重载。但是,run()函数创建了一个ObserverExample类的实例是什么情况?只有函数才能重复调用自己,一个类里面不能创建自己的实例。
在调用constructor创建ObserverExample类的实例之后,马上用dotted notation调用了ObserverExample类的start()函数,也就是本段代码中的start()函数。这又是神马情况?Constructor后面一般都不会有dotted notation的。
综上所述,本黄鸭决定放弃这段代码,继续往下看。
MainWindow中有一个attribute,类型是JLabel,名字叫做label。这个类的构造函数相当于View类的构造函数,规定了label显示什么,以及显示在什么位置上。
接下来还有一个method,名字是update(),是ObserverInterface中定义的一个abstract的函数,这里需要重载。函数体的功能是把label中显示的字符串替换为新的。
MessageObservable是ObservableInterface的子类,里面没有attribute,构造函数返回的是它的父类的指针,即ObservableInterface的object reference。
还有一个method是changeData(),这个函数没有被定义在ObservableInterface中,所以是用户自己定义的。函数体调用了两个Observable的函数,分别是setChanged(),让“changed”flag立起来;notifyObservers(),把数据发生变化的事实告诉observers。
DialogWindow有一个attributes,类型是int,名称是clicks,功能是记录一共点击了多少次按钮的计数器。
构造函数接收的参数是Observer的子类,所以要把Observer加入到Observable中去。这样,在Observable发生变化的时候,会自动通知到Observer,让它update界面上的字符串。
DialogWindow类中也有界面显示,编写在constructor中。一个叫做“Dialog”的窗口中,有一个叫做“Press me”的按钮。这个按钮上有监听器,按下按钮以后会累加点击的次数到clicks attribute,而且会告知Observable类,最后通知到Observer。Observer会自动调用update()函数,把界面上的字符串更新一下。
欢迎使用本黄鸭编写的小程序~
微信公众号二维码:
领取专属 10元无门槛券
私享最新 技术干货