Java Swing设计指南 [英] Java Swing Design Guide

查看:141
本文介绍了Java Swing设计指南的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 
+ ---------------------- +
| MainClass(s​​tatic)|
| ---------------------- |
+ ------ + -DataList + ----- +
| | | |
static | + - + -------------- + ----- + | static
reference | | |参考
| | 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 可以在 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。所以我的问题是:你如何设计这个和你可以给我的哪些通用指针?

解决方案

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



您还可以杀死可测试性。 >

分别处理GUI和应用程序逻辑 - 不要在您的应用程序逻辑(exec类)中考虑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(逻辑,窗口);
}

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



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

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

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

  window.setProcessingController(controller); 

...

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

现在你有窗口和控制器的双向通信。 >

这些是基本要点,它为您提供了可测试性和使用尽可能多的逻辑/控制器/窗口的能力。您也可以使用松散耦合的组件:您可以为测试目的注入几乎为空的AppLogic存根,或者在测试中模拟用户界面。当然要分配组件,你应该提取界面并提供具体的实现:

  SwingAppWindow实现ApplicationUserInterface {... 
SQLDataManager实现ApplicationDataLogic {...
BasicController实现ProcessingController {...

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



并且记住,所有的gui操作(事件,更新)都应该运行摆动事件线程,所以你应该使用SwingUtils,beacuse swing不是线程安全

  SwingUtilities。 invokeLater(new Runnable(){
public void run(){
....排队的动作改变gui ...
}
});

记住不要使用新的在您的逻辑类中,例如不要在控制器中使新窗口新的ApplicationDataModel - 因为您不能独立测试您的控制器或重复使用不同的逻辑/窗口实现 - 您只能创建一些类来准备应用程序依赖项(创建组件并链接它们)和启动它 - 它通常称为工厂



如果您的逻辑增长并变得更加复杂,将其分解为更多的服务对象,您可以使用命令模式在您的gui中生成命令并处理它(例如在线程安全队列中)在应用程序服务中 - 这也将是恢复/重做能力的良好起点。



最后一个事情 - 如果你有任何长时间运行的处理任务(即使花了1秒,我们可以说这是长时间运行的),重新计算帽子直接调用它或在swingUtils将冻结你的gui,所以对于lenghty操作创建单独的线程与线程,执行器,Runnable,SwingWorker或某事(你可以使用观察者模式来监视进度等)。

$ b $请记住,这真的是一个很大的话题,这个帖子只提到一些小的一般建议。



要采取的其他道路可以使用已经提供的架构来创建像Eclipse RCP或Netbeans Platform这样的GUI应用程序。


I have written an application that is using Swing for the GUI, accepts a file via the GUI, parses the Input, saves it in DataList and sends it to a server. I'm concerned about the whole design of my program, which I don't think is very good. I'm using Netbeans to design the GUI and have a class MainClass that starts that GUI and has a static reference to the GUI. Also there are a couple of ExecClasses that do the aforementioned parsing and sending of the data.

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

Here a short overview of the 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);
  }

I'm using these references so that the SwingGUIClass can execute a method in the ExecClass1 for example. I chose this approach since I have a TextArea that needs to get the data out of one of the ExecClasses and display it in the GUI. Since I can't modify the TextArea from the ExecClass.

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());
}

I understand that this is a far from great design and not following a couple of good practice guides, e.g. MVC. So my question is : How would you design this and which general pointers can you give me?

解决方案

First of all, don't do logic based on static references on things, that you can use in multiple context. For example in future, you can have a requirement to have several windows of your GUI interfaces interacting with several instances of your services.

Also you are killing testability.

Treat GUI and application logic separately - don't think in your application logic (exec classes) about GUI text field etc. Just think about input and output, and provide a class to communicate each other (the controller). You can provide data to application logic in controller, get results and display it in GUI like:

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

Your components should be loose coupled, so you can reuse and test them. You can achieve that with simple dependency injection like putting your dependencies in contructors/setters:

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

This is very simple draft of controller initializning method. With that, you can test/reuse your logic or your GUI in other places like unit tests.

To move bussiness logic from your window, where all events are fired (buttons etc.) you can create a interface, which will work with your window:

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

And you can implement this logic in your controler (implements) and use it as GUI events receiver:

window.setProcessingController( controller );

...

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

And now you have two-way communication with window and controller.

Those are basic points, that gives you testability and ability to make as much logic/controller/windows as you want. Also you have loose coupled components: you can inject a almost-empty stub of AppLogic for test purposes or faked AppWindow to simulate user acions in test. Of course to subsitute components, you should extract interfeces and provide specific implementations:

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

Of course you can split it even further to separate data access and bussines logic.

And remeber that all your gui actions (events, updates) should run in swing event thread, so you should use SwingUtils, beacuse swing is not thread safe:

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

Remeber to not hard-code object instantation with new in your logic classes, for example don't make new Window and new ApplicationDataModel in your controller - because you can't test your controller independly or reuse it with different logic/window implementation - you can create some class only to prepare your application dependencies (create components and link them) and "start it" - it's generally called a factory.

If your logic will grown and become more complicated, split it into more service objects and you can use a command pattern to produce commands in your gui and process it (for example in thread safe queue) in application services - which also will be good starting point to undo/redo ability.

Last one thing - if you have any long running processing task (even if it took 1 second we can say that it's long running), remeber that invoking it directly or in swingUtils will freeze your gui, so for lenghty operations create separate threads with a Thread, Executors, Runnable, SwingWorker or something (you can use a observer pattern to monitor progress etc).

Have in mind that this is really a big topic and this post mention only some small general advices.

The "other road" to take can be to use a already provided architecture to create GUI application like Eclipse RCP or Netbeans Platform.

这篇关于Java Swing设计指南的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆