如何在不使用Spring等时将Swing GUI与Business Logic分开

Ste*_*o L 7 java oop swing cohesion decoupling

请注意,这是一篇很长的帖子.对不起,但我想澄清一点:

我想知道如何将Swing GUI与Presentation和Business Logic分开很长一段时间.在工作中,我必须使用一个小的Swing对话框为一些数据实现3 MD Excel Export以配置导出.我们不使用像Spring这样的框架,所以我必须自己实现它.

我想完全将GUI与Business Logic分开,这些都是精确的后续任务:

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

当然,GUI不应该注意BL实现,反之亦然.我创建了上述所有这些任务,例如几个接口ProgressListener,LogMessageListener,JobDoneListener等,要由业务逻辑被解雇.例如,如果业务逻辑想要告诉记录,则会调用

fireLogListeners("Job has been started");
Run Code Online (Sandbox Code Playgroud)

实现公共接口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.
}
Run Code Online (Sandbox Code Playgroud)

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

exportJob.addProgressListener(uiDialog);
exportJob.addLogListener(uiDialog);
exportJob.addJobFinishedListener(uiDialog);
exportJob.start();
Run Code Online (Sandbox Code Playgroud)

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

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

Oli*_*ins 2

一些东西。

我不会在 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);
}
Run Code Online (Sandbox Code Playgroud)

(不需要 Swing.invokeLater())

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

而不是这个:

button.addActionListener(new ActionListener() {

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

});
Run Code Online (Sandbox Code Playgroud)

为什么不只是:

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

button.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        exportJob.start();
    }
});
Run Code Online (Sandbox Code Playgroud)

这样你就可以摆脱 ExportFunction ,它实际上没有任何用途。

你似乎有很多听众。除非你真的需要它们,否则我不会打扰它们并使其尽可能简单。

代替 :

Thread.sleep(1000);
fireLogListener("Excel Sheet 2 created");
Thread.sleep(1000);
Run Code Online (Sandbox Code Playgroud)

只要有:

Thread.sleep(1000);
log("Excelt Sheet 1 created");
Thread.sleep(1000);
Run Code Online (Sandbox Code Playgroud)

其中日志是:

private void log(final String message) {
    ((DefaultListModel<String>) list.getModel()).addElement(message);
}
Run Code Online (Sandbox Code Playgroud)

这样你就可以让它变得更简单、更干净。

GUI 不应该知道 BL,但 BL 必须以某种方式告诉 GUI 做什么。您可以使用大量接口进行无限抽象,但在 99.99% 的应用程序中这是不必要的,尤其是您的应用程序,它看起来相当简单。

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