2

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

                 +------------------------+
                 | MainClass (静态) |
                 |-------------------------|
          +------+ -数据列表 +-----+
          | | | |
    静态| +-+--------------+-----+ |静态
  参考 | | |参考
          | |新 () | 新 () |
          | | | |
          | | | |
        +-+--------v----+ +--v------------+--+
        | | | |
        | SwingGUI类 | | 执行类 |
        | | | |
        +---/\-----------+ +-----------------+
           |
          输入文件

这里是一个简短的概述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可以执行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());
}

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

4

1 回答 1

7

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

你也在扼杀可测试性。

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

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

您的组件应该是松耦合的,因此您可以重用和测试它们。您可以通过简单的依赖注入来实现这一点,例如将依赖项放入构造器/设置器中:

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

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

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

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 { ...

当然,您可以进一步将其拆分为单独的数据访问和业务逻辑

请记住,您的所有 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,所以对于冗长的操作创建单独的线程Thread、Executors、Runnable、SwingWorker 或其他东西(您可以使用观察者模式来监控进度等)。

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

“另一条路”可以是使用已经提供的架构来创建 GUI 应用程序,如 Eclipse RCP 或 Netbeans 平台。

于 2013-09-25T10:55:47.963 回答