Java Swing设计指南

我编写了一个使用Swing for GUI的应用程序,通过GUI接受文件,解析Input,将其保存在DataList并将其发送到服务器。 我关心我的程序的整个设计,我认为这不是很好。 我正在使用Netbeans来设计GUI,并有一个MainClass类,它启动该GUI并具有GUI的静态引用。 还有一些ExecClasses执行上述解析和发送数据。

                  + ---------------------- +
                  |  MainClass(静态)|
                  | ---------------------- |
           + ------ + -DataList + ----- +
           |  |  |  |
    静态|  +  -  + -------------- + ----- + |静态
  参考|  |  |引用
           |  | new()|  new()|
           |  |  |  |
           |  |  |  |
         +  -  + -------- v ---- + +  -  v ----------- +  -  +
         |  |  |  |
         |  SwingGUIClass |  |  ExecClasses |
         |  |  |  |
         +  -  / \ ----------- + + ----------------- +
            |
          输入文件

这里是MainClass的简短概述:

 public class MainClass { private static MainClass mainClass; private static ExecClass1 ex1; private static ExecClass2 ex2; private static ExecClass3 ex3; public static void startExecClass2(String param){ ex2 = new ExecClass2(param); } 

我正在使用这些引用,以便SwingGUIClass可以在SwingGUIClass中执行一个方法。 我选择了这种方法,因为我有一个TextArea需要从其中一个ExecClasses中获取数据并将其显示在GUI中。 因为我无法从ExecClass修改TextArea。

 public class SwingGUIClass { [...] private void ButtonActionPerformed(java.awt.event.ActionEvent evt) { Label.setText(MainClass.getList()); } private void Button2ActionPerformed(java.awt.event.ActionEvent evt) { MainClass.startExecClass2(Button2.getText()); } 

我知道这远非伟大的设计,并没有遵循一些良好的实践指南,例如MVC。 所以我的问题是: 你如何设计这个以及你可以给我哪些一般指示?

首先,不要在事物上做静态引用的逻辑,可以在多个上下文中使用。 例如,将来,您可以要求GUI界面的多个窗口与您的多个服务实例交互。

你也在杀死可测试性。

分别处理GUI和应用程序逻辑 – 不要在应用程序逻辑(exec类)中考虑GUI文本字段等。只需考虑输入和输出,并提供一个相互通信的类(控制器)。 您可以向控制器中的应用程序逻辑提供数据,获取结果并在GUI中显示,如:

 public void processFile( SomeInputFromGui input ) { SomeResult result = applicationLogicObject.process( input ); guiObject.showResult( result ); } 

您的组件应该是松耦合的,因此您可以重用并测试它们。 您可以通过简单的dependency injection实现这一点,例如将依赖项放在contructors / setter中:

 public void initApplication() { AppLogic logic = new AppLogic(); AppWindow window = new AppWindow(); AppController controller = new Controller( logic , window ); } 

这是控制器初始化方法的非常简单的草案。 有了它,您可以在其他地方测试/重用您的逻辑或GUI,例如unit testing。

要从窗口中移动业务逻辑,触发所有事件(按钮等),您可以创建一个适用于您的窗口的界面:

 public interface ProcessingController { public void processFile( File x ); public void checkIntegrity(); public SomeDataValues getCurrentDataValues(); } 

您可以在控制器( implements )中实现此逻辑,并将其用作GUI事件接收器:

 window.setProcessingController( controller ); 

 private void ButtonActionPerformed(java.awt.event.ActionEvent evt) { processingController.processText( jMyTextField.getText() ); } 

现在,您可以与窗口和控制器进行双向通信。

这些是基本点,为您提供可测试性和能力,使您可以根据需要制作尽可能多的逻辑/控制器/窗口。 此外,您还有松耦合组件:您可以为测试目的注入几乎空的AppLogic存根,或者伪造AppWindow以模拟测试中的用户操作。 当然要替换组件,您应该提取干扰并提供特定的实现:

 SwingAppWindow implements ApplicationUserInterface { ... SQLDataManager implements ApplicationDataLogic { ... BasicController implements ProcessingController { ... 

当然,您可以进一步拆分它以分离数据访问和bussines逻辑

并记住你所有的gui动作(事件,更新)应该在swing事件线程中运行,所以你应该使用SwingUtils,因为swing不是线程安全的

 SwingUtilities.invokeLater(new Runnable() { public void run() { .... queued action that changes the gui ... } }); 

记住不要在逻辑类中使用new硬编码对象即时,例如不要在控制器中创建new Windownew ApplicationDataModel – 因为你不能独立地测试你的控制器或者在不同的逻辑/窗口实现中重用它 – 你可以创建一些类只是为了准备你的应用程序依赖项(创建组件并链接它们)和“启动它” – 它通常被称为工厂

如果你的逻辑会增长并变得更加复杂,可以将它分成更多的服务对象,你可以使用命令模式在你的gui中生成命令并在应用程序服务中处理它(例如在线程安全队列中) – 这也是很好的开始指向撤消/重做能力。

最后一件事 – 如果你有任何长时间运行的处理任务(即使花了1秒我们可以说它已经运行很长时间),记住直接调用它或在swingUtils中会冻结你的gui,所以对于lenghty操作创建单独的线程Thread,Executors,Runnable,SwingWorker等(你可以使用观察者模式来监控进度等)。

请记住,这确实是一个很大的话题,本文仅提到一些小的一般性建议。

要采取的“其他方法”可以是使用已经提供的架构来创建Eclipse RCP或Netbeans Platform等GUI应用程序。