Java Swing设计指南

cet*_*te3 2 java user-interface swing design-patterns

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

                 +----------------------+
                 | MainClass (static)   |
                 |----------------------|
          +------+  -DataList           +-----+
          |      |                      |     |
    static|      +-+--------------+-----+     |static
  reference        |              |           |reference
          |        |new ()        | new ()    |
          |        |              |           |
          |        |              |           |
        +-+--------v----+      +--v-----------+--+
        |               |      |                 |
        | SwingGUIClass |      | ExecClasses     |
        |               |      |                 |
        +--/\-----------+      +-----------------+
           |
          Input file

这里简要概述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);
  }
Run Code Online (Sandbox Code Playgroud)

我正在使用这些引用,以便SwingGUIClass可以在ExecClass1例如执行方法.我之所以选择这种方法是因为我有一个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());
}
Run Code Online (Sandbox Code Playgroud)

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

Pio*_*ler 7

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

你也在扼杀可测试性.

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

public void processFile( SomeInputFromGui input ) {
 SomeResult result = applicationLogicObject.process( input );
 guiObject.showResult( result );
}
Run Code Online (Sandbox Code Playgroud)

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

public void initApplication() {
  AppLogic logic = new AppLogic();
  AppWindow window = new AppWindow();
  AppController controller = new Controller( logic , window );
}
Run Code Online (Sandbox Code Playgroud)

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

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

public interface ProcessingController {
public void processFile( File x );
public void checkIntegrity();
public SomeDataValues getCurrentDataValues();
}
Run Code Online (Sandbox Code Playgroud)

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

window.setProcessingController( controller );
Run Code Online (Sandbox Code Playgroud)

...

private void ButtonActionPerformed(java.awt.event.ActionEvent evt) { 
   processingController.processText( jMyTextField.getText() );
}
Run Code Online (Sandbox Code Playgroud)

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

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

SwingAppWindow implements ApplicationUserInterface { ...
SQLDataManager implements ApplicationDataLogic { ...
BasicController implements ProcessingController { ...
Run Code Online (Sandbox Code Playgroud)

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

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

SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      .... queued action that changes the gui ...
    }
  });
Run Code Online (Sandbox Code Playgroud)

Remeber与不硬编码对象instantation new在你的逻辑类,例如不要让new Windownew ApplicationDataModel在您的控制器-因为你不能independly测试你的控制器或者与不同的逻辑/窗口实现重用-你只能创建一些类准备你的应用程序依赖项(创建组件并链接它们)和"启动它" - 它通常被称为工厂.

如果您的逻辑将变得更加复杂,请将其拆分为更多服务对象,您可以使用命令模式在gui中生成命令并在应用程序服务中处理它(例如在线程安全队列中) - 这也将是一个好的开始指向撤消/重做能力.

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

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

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