java - 不使用Spring等时如何将Swing GUI与业务逻辑分离

标签 java swing oop decoupling cohesion

请注意,这是一篇很长的文章。很抱歉,但我想阐明我的观点:

很长一段时间以来,我一直在想如何将 Swing GUI 与表示和业务逻辑分开。 在工作中,我必须为一些数据实现 3 MD Excel 导出,并使用一个小的 Swing 对话框来配置导出。 我们没有为此使用像 Spring 这样的框架,所以我必须自己实现它。

我想将 GUI 与业务逻辑完全分开,它们的任务如下:

  • 告诉 BL 从 GUI 开始工作
  • 从 BL 到 GUI 报告进度
  • 报告从 BL 到 GUI 的日志记录
  • 将 BL 结果委托(delegate)给 GUI

当然,GUI 不应该注意到 BL 的实现,反之亦然。 我为上面的所有这些任务创建了几个接口(interface),e。 G。一个 ProgressListenerLogMessageListenerJobDoneListener, 等等,由业务逻辑触发。例如,如果业务逻辑想要讲述日志记录,它会调用

fireLogListeners("Job has been started");

实现公共(public)接口(interface) LogListener + 的类附加到 BL,现在将通知“作业已启动”日志消息。 所有这些监听器此时都由 GUI 本身实现,通常看起来像这样:

public class ExportDialog extends JDialog implements ProgressListener, LogListener, JobFinishedListener,  ErrorListener {

    @Override
    public void jobFinished(Object result){
        // Create Save File dialog and save exported Data to file.
    }

    @Override
    public void reportProgress(int steps){
        progressBar.setValue(progressBar.getValue()+steps);
    }

    @Override
    public void errorOccured(Exception ex, String additionalMessage){
        ExceptionDialog dialog = new ExceptionDialog(additionalMessage, ex);
        dialog.open();
    }

    // etc.
}

“GUI 和 BL 创建类”只是将 GUI(作为所有这些监听器的界面)附加到 BL,看起来像这样:

exportJob.addProgressListener(uiDialog);
exportJob.addLogListener(uiDialog);
exportJob.addJobFinishedListener(uiDialog);
exportJob.start();

我现在对此非常不确定,因为它看起来很奇怪,因为所有这些新创建的监听器接口(interface)。 你有什么想法? 如何将 Swing GUI 组件与 BL 分开?

编辑: 为了更好地演示,我在 eclipse file-upload.net/download-9065013/exampleWorkspace.zip.html 中创建了一个演示工作区 我也将它粘贴到 pastebin,但最好在 eclipse 中导入这些类,相当多的代码 http://pastebin.com/LR51UmMp

最佳答案

一些事情。

我不会在 ExportFunction 类中包含 uiDialog 代码。整个执行方法应该只是主类中的代码。 ExportFunctions 的责任是“导出”而不是“显示 gui”。

public static void main(String[] args) {
    ExportFunction exporter = new ExportFunction();

    final ExportUIDialog uiDialog = new ExportUIDialog();
    uiDialog.addActionPerformedListener(exporter);

    uiDialog.pack();
    uiDialog.setVisible(true);
}

(不需要 Swing.invokeLater())

您似乎设计过度了。我不知道为什么您会期望同时运行多个线程。当您按下按钮时,您只会期望一个线程运行,对吗?那么就不需要 actionPerformedListener 数组了。

而不是这个:

button.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent arg0) {
        if (startConditionsFulfilled()) {
            fireActionListener(ActionPerformedListener.STARTJOB);
        }
    }

});

为什么不只是:

final ExportJob exportJob = new ExportJob();
exportJob.addJobFinishedListener(this);
exportJob.addLogListener(this);

button.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        exportJob.start();
    }
});

这样您就可以摆脱实际上没有任何作用的 ExportFunction。

您似乎有很多听众数组。除非你真的真的需要它们,否则我不会为它们操心,并尽可能简单。

代替:

Thread.sleep(1000);
fireLogListener("Excel Sheet 2 created");
Thread.sleep(1000);

只需:

Thread.sleep(1000);
log("Excelt Sheet 1 created");
Thread.sleep(1000);

日志在哪里:

private void log(final String message) {
    ((DefaultListModel<String>) list.getModel()).addElement(message);
}

通过这种方式,您可以使它更简单、更清晰。

GUI 不应该知道 BL,但 BL 必须以某种方式告诉 GUI 做什么。您可以无限地抽象出许多接口(interface),但在 99.99% 的应用程序中,这不是必需的,尤其是您的应用程序,它看起来相当简单。

因此,虽然您编写的代码非常好,但我会尝试简化和减少接口(interface)。它不需要那么多工程。

关于java - 不使用Spring等时如何将Swing GUI与业务逻辑分离,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24228513/

相关文章:

java - 计算图像位移 - Java

java - 球不会在屏幕上移动

c++ - 如何将对象插入到 std::vector 中?

java - 构建器模式是否适用此要求?

java - 如何在 Spring MVC 的请求映射中始终返回用户所在的当前页面?

java - 试图找出为什么这两个 SOAP 请求之一不起作用 (java.lang.IllegalArgumentException)

java - 在不同时区操作 JCalendar

java - 使用线程时 Swing GUI 卡住

c++ - 在指向现有内存地址的 hpp 文件中声明成员函数的最佳方法

java - 通过 cli 参数填充 mojo 的文件集