Swing程序最佳架构设计—以业务对象为中心的MVC模式

    技术2022-05-11  64

            Swing 程序最佳架构设计 以业务对象为中心的 MVC 模式     前言: 我打算写一系列关于Swing程序开发的文章。这是由于最近我在做一个Swing产品的开发。长期做JavaEE程序,让我有些麻木了。Swing是设计模式的典范,是一件优雅的艺术品,是一件超越时代的产品! 有机会作Swing软件的开发,让我非常有感觉! 呵呵,希望有机会能够用Java3D编写软件,那种感觉一定更棒! Java和Swing都是杰作。我这个人对别人一向很挑剔的,能够得到我由衷地赞誉,可想而知它们有多优秀了。奇怪的是,它们居然一直都无法占领桌面市场。有人说这是技术的原因。我认为这应该是商业、历史的原因才对。 好了,我也应该为java和Swing在桌面的成功尽我绵薄之力,共享我的思想吧!以感谢这么多年来,Java带给我的美好回忆。 台灯、电脑、Java,还有Coffee,伴我度过多少不眠之夜!I love U!       Swing 程序最佳架构设计之一                        业务模型中心架构模式   以业务模型为中心 以业务模型为中心的架构模式。这是Swing和其他所有程序应该采用的架构模式。之所以强调Swing,是因为在Swing程序中使用这种“以业务模型为中心”的架构模式,更有意义,作用更大! 我们知道,一个软件由几个部分组成: 1,表现层(用户界面层) 这时软件和用户交互的部分,可以分为字符界面(DOS等命令行),GUI图形界面(桌面GUI,浏览器GUI,三维界面)等。 这仅仅是软件的外表,外貌再华丽,也不能说明软件的优劣!Google的界面平淡无奇,但它确是今天最强大的软件!   2,业务层 这是实现软件功能的地方。存在着大量映射着业务领域的对象,存在着复杂的业务计算。这才是软件真正工作的地方。 软件的核心和难点就在这里!巨大的开发工作量和思考,也都集中在这里。 业务模型,及其互相之间的交互,这才是软件的核心!   3,数据库访问层(可能有) 有些软件需要把操作保存进数据库,永久保留下来。通常,企业级等需要业务数据的软件需要这个模块。 它实现业务对象和关系型数据库的映射。称为“O-R”映射。   4,持久化层(可能有) 有些软件不把数据保存进数据库,而是保存为文件。如,二进制文件,文本文件,XML文件等。 它实现业务对象和文件之间的映射。可能是序列化业务对象。如果是保存为xml文件,我们称它为O-XML映射,是业务对象和XML文件之间的映射。 现在有一些开源软件实现了Java对象和XML文件之间的映射,就如同是O-R映射一样。其实,基于Java的XML访问组件,自己开发O-XML映射也是非常简单的,我自己也写了一个这样的库。   可以看到,“以业务模型为中心”,并不是一种特例,而是最基本的软件开发规律!是所有软件共有的基本特性。只是,今天,在各自不同的领域,这个基本常识被一些常用的领域中的架构模式所模糊了。 如,在Java的企业级软件开发中,大家都知道J2EE软件分为3层: 1,表现层 2,业务层-----业务对象和Service助手类 3,数据库访问层-----DAO助手类 这样的架构模式,模糊了“业务对象”是整个软件的核心这样一个事实。 Service助手类和DAO助手类,实际上都是业务对象的一部分,完全可以被放在业务类中。 助手类和业务对象分离,不过是一种设计模式而已。     Swing程序中的应用 好了,本文并不想讨论这些“形而上学”的问题。上面的讨论,不过是想让你明白,本文所论述的“以业务模型为中心”的架构模式,并不是Swing应用程序所特有的,而是所有软件的特性,只是,在Swing这个条件优越的桌面开发环境中,更加有用罢了!   Swing程序作为桌面程序,拥有比JavaEE程序更好的环境,更强的功能。 Swing程序常常是单机的,即使是网络化的,也可以在业务层中实现分布式,而不像JavaEE程序,用户界面和响应用户操作的代码都是分布在不同的机器上的! 因此,Swing程序更能发挥我们软件开发者的智慧和能力!     Swing 程序最佳架构设计之二                        MVC 模式     Swing程序的组成 一般,Swing程序由以下几部分组成: 1,表现层----Swing组件组成的GUI 2,业务层------业务对象,及其相互之间的关系 3,持久化层-----把业务对象保存为文件,或者是数据库记录。 MVC模式在Swing程序中的应用 我们知道,Swing是MVC模式的典范。Swing的各个可视化组件都使用MVC模式来设计。 Swing组件一般由三个部分组成: 1,Swing的Model,这是MVC中的M—模型部分。它保存了Swing组件所需要的数据。Swing组件的UI需要根据它来展现。 2,Swing的UI类。这是MVC模式的View—视图部分。它根据组件的Model中的数据,执行绘制、展现Swing组件的任务。 3,Swing组件类。这是“门面”,它封装了Swing的UI对象和Model对象。我们一般都是通过它来操纵Swing组件,不会直接使用Swing组件内部的UI对象和Model对象。 Swing组件之间,还有着复杂的关系。Swing的UI类,监听Model对象的数据改变,即时进行重绘界面的工作。 在Swing组件上还可以注册一系列的事件监听器。它们就是MVC模式中的Controller控制器。   Swing应用程序中使用MVC模式 一个Swing应用程序的GUI由很多个Swing组件组成。各个Swing组件本身是由MVC模式设计的,而我们的整个Swing应用程序的表现层也应该由MVC模式设计。 使用MVC模式,能够更好地分离代码和数据。使整个应用的表现层部分,更加低耦合、高内聚,灵活度更高。 在Swing应用程序的编写过程中,我们需要使用Swing组件的2个部分: 1,Swing组件的Model。Swing组件的MVC模式设计,使整个Swing组件是以Model为核心的。通过更改Model,我们就能够即时改变Swing组件的UI外观。 2,Swing组件上注册事件监听器。这是Swing组件的控制器,也可以作为整个Swing程序的控制器之一。     在Swing组件的监听器中,我们可以响应用户的操作,作为整个程序功能的入口。在这里,我们可以调用业务层的代码进行业务计算。计算完毕之后,可以修改Swing程序的外观。常常是修改某个Swing组件的Model。     Swing组件的监听器,一般是使用Swing程序的内部类来实现的。因此,我们可以在控制器中完全使用整个Swing程序的所有资源!因此,Swing组件的控制器是足够足够强大的!   此Model非彼Model 读者应该对JavaEE比较熟悉吧。毕竟,今天Java的主战场是在企业级应用上,会java,而不懂javaEE,这就有点说不过去了。 这里,我以大家比较熟悉的JavaEE的表现层技术来说明Swing程序的MVC设计。 Struts中,其MVC由以下几部分组成: 1,View视图,就是使用Struts标签的JSP页面。 2,Controller控制器,就是响应用户操作的Action。 3,Model模型,就是用户html页面表单中提交的数据。这在Struts中被称为“form”表单。 HTML表单的数据,都是String型的,而我们的业务对象的属性,却未必都是String型的。因此,在Struts应用程序中,我们需要根据接收到的form对象,构造业务对象。 在SpringMVC中,提供了一个机制,可以帮助我们自动把表单数据转为业务对象。对于一些特殊的类型转换,还是需要我们手工提供转换。 Form和业务对象之间的自动转换,固然是提高了开发效率。但是,我们必须要明白,GUI组件中的数据Form和业务对象是截然不同的两种东西。2者碰巧一样,或者可以自动转换,只是特例。它们本质上还是两样截然不同的东西。 Form是表现层的数据容器,而业务对象则是来自于特定业务的对象。Form的数据类型,变化不多,而业务对象的数据类型,那就是千变万化了。 因此,Form对象类型和业务对象类型一致,这是少之又少的特例。   Swing程序中的表单数据(Form)和业务对象(Model) Web应用程序中的表单数据form,是来自于Html的表单的各个项的数据,都是String类型。 Swing程序中的表单数据Form。是由Swing程序的各个Swing组件的Model组成的。其各个部分的数据类型非常不同。 如,最简单的文本框JTextField的Model,是 javax.swing.text.Document类型的对象。这个对象,我们也可以直接得到或设置String的值来作为Model。实际上这个String类型的数据,是Document的属性。 还有,如JTree组件的Model是TreeModel对象。 因此,Swing程序中的表单数据Form的类型是非常多的。显然,我们的业务对象不大可能和Swing的Form数据的类型一致。 因此,Swing程序的表现层的数据Form和业务对象Model之间的转换,必然要由我们自己去实现。不大可能直接把Form作为业务对象扔到业务层中使用。也不可能直接在Swing的GUI中显示业务对象的数据!   Swing程序的MVC模式的使用 整个Swing程序应该这样使用MVC模式: 1,JFrame或者其他顶层容器中,由各个Swing组件构成了View视图层。用来展现数据,提供用户操作的图形界面。   2,一个或者一组业务对象是Model。它们存放了Swing组件要显示的数据。它们是业务对象,因此,可以直接在业务层代码中使用,执行复杂的业务计算。 它们不能直接在Swing组件中显示。而是需要根据业务对象,构造Form对象,也就是Swing组件的Model来展示数据。 为了让View—Swing组件实时展现业务对象的数据,我们需要让Swing组件监听业务对象,一旦业务对象发生改变,就重新根据新的数据,构建新的Swing组件的Model,从而在Swing组件上展现最新的业务对象数据。 这里,我们使用 ChangeListener 改变监听器。 为了让业务对象能够得到用户最新输入的数据,我们还需要将业务对象注册到Swing组件上。一旦Swing组件的数据发生了改变,就通知业务对象。业务对象根据Swing组件的Model,也就是Form对象的数据,修改业务对象的值。 为了实现这样的功能,我也使用了事件机制,实现了这一功能。这将在下文中论述。 现在,业务对象和Swing组件之间,通过双向的事件监听机制,实现了双向的引用!   3,在Swing各个组件上注册响应事件的监听器(控制器),以响应用户的操作。这些控制器,使用匿名内部类实现。 每一个Swing组件上的控制器,都不仅仅是该Swing组件的控制器,而是整个Swing程序的控制器。因为,内部类可以操纵整个Swing程序的所有资源,因此,我们可以在控制器中,使用所有Swing组件的form,也可以使用所有业务对象,调用所有业务方法,实现任何需要的功能! 控制器,是业务功能的入口点,它连接了Swing程序的表现层和业务层,连接了Swing的Form(Swing组件的Model)和业务对象。   现在,我们的Swing程序结构清晰,功能区分合理,低耦合、高内聚,堪称是MVC模式的典范!     Swing组件和业务对象之间的互动关系 在上文中,我们提出了Swing组件和业务对象之间相互的事件监听机制。Swing组件监听业务对象,使用“观察者模式”的一种实现机制,ChangeListener改变监听器。当然,也可以使用Observe/Observable这样的机制,或者其它的事件机制。但是,经过权衡,我觉得还是ChangeListener最符合我的需要。它功能强大,又很简单。 当我们需要某个Swing组件监听我们的业务对象时,我们创建一个该Swing组件的子类,它实现ChangeListener接口,实现 public void stateChanged(ChangeEvent e){…}方法,根据监听的业务对象的数据,构建自己新的Model,从而改变本Swing组件的显示。   业务对象又该怎样监听Swing组件呢? 我钟爱ChangeListener,还是在Swing组件上注册一个ChangeListener监听器,这个监听器就是我们的业务对象。 但是,考虑到ChangeListener使用场合甚广,为了避免Swing组件的其他操作激发该事件,我参照ChangeListener接口,新建了一个类型的新接口:ControllerChangeListener接口。 现在,Swing组件上的数据就能够和我们的业务对象的数据保持同步了!Form和业务对象虽然类型不同,却好像是同一个对象,有着同样的数据!   采用MVC模式后的Swing程序的执行流程 1,用户可以看到一个Swing组件构成的GUI界面。 2,用户在界面上进行操作。 3,Swing组件的控制器被触发。 1)可能会激发ControllerChangeListener的事件,引起业务对象自动使用Swing组件的Model数据进行更新。 2)业务对象更新数据,又会激发业务对象上的ChangeListener的事件。这会引起所有监听业务对象其Swing组件更新其Model的数据,从而改变Swing组件的显示。 3)我们可能会针对业务对象,执行业务层代码,进行复杂的业务计算。得到新的业务对象的值。     这同样会激发业务对象的ChangeListener事件,让Swing组件的Model得到更新,从而改变Swing组件显示的界面。 4)最后,当然,我们也可以直接修改某些Swing组件的Model或者外观。因为,作为内部类的控制器可以使用Swing程序所有的属性和方法。 在我的 《Swing多线程编程》一文中,我论述过Swing程序中,应该将SwingUI处理代码和一般的业务代码分配在不同的线程中。 所以,在这里的控制器中,我们应该使用SwingWorker这个助手类,把业务代码放在 public Object construct() {…} 方法中执行, 而把直接修改 Swing 组件 UI 的方法,放到 public void finished() {…} 方法中执行。这样, Swing 程序的交互性、响应能力和性能将大大提高!   可以看到,这里,通过将业务对象和Form对象(Swing组件的Model)关联起来,我们在Swing应用程序中只需要“以业务对象为中心”。操纵业务对象,执行业务操作即可。 Swing程序的用户界面,就会自动更新。 这就是采用“以业务对象为中心的MVC模式”的巨大优势!                       良少 认证博客专家 数据分析 PyTorch 神经网络 资深挨踢人士,精通Python,C,Java,JavaScript,Linux内核,网络协议,虚拟化,云计算,分布式存储,kubernetes,数据仓库等技术。擅长微服务架构设计,DevOps。目前致力于以Fintech助力普惠金融。

    最新回复(0)