2013-09-25 230 views
2

我已經編寫了一個應用程序,該應用程序使用Swing作爲GUI,通過GUI接受文件,解析輸入並將其保存在DataList中並將其發送到服務器。我很擔心我的程序的整個設計,我認爲這不是很好。我正在使用Netbeans來設計GUI,並且有一個類MainClass,它啓動該GUI並具有對GUI的靜態引用。還有幾個做上述解析和數據發送的ExecClassesJava Swing設計指南

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

我使用這些引用,以便SwingGUIClass可以執行在ExecClass1例如方法。我選擇了這種方法,因爲我有一個TextArea,需要從其中一個ExecClass中獲取數據並將其顯示在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。所以我的問題是:你會怎樣設計這個以及你能給我哪個一般指針?

+1

它是一個廣泛的主題,與Swing沒有嚴格關係:-)而且有很多可能性 - 你可能想從f.i開始。在[馬丁福勒的關於表達邏輯的系列](http://martinfowler.com/eaaDev/OrganizingPresentations.html)順便說一句:請學習java命名約定,並堅持他們 – kleopatra

+0

@kleopatra首先,感謝您的鏈接 - 我會看看進去。當然,我在這裏發佈的代碼並不是實際的代碼,爲了讓不熟悉我的程序的人更容易理解,或者你指的是其他的東西,我將類/變量(MainClas,ex2)重命名爲? – cete3

+0

好像你缺少模型對象。不像Swing讓他們很容易處理。考慮使用支持綁定的Java FX。 – millimoose

回答

7

首先,基於對事物的靜態引用不這樣做的邏輯,你可以在多種環境中使用。例如,將來您可以要求GUI界面的多個窗口與您的服務的多個實例進行交互。

你也在殺死可測性。

分開處理GUI和應用邏輯 - 不認爲在約GUI文本字段等應用程序邏輯(EXEC班)試想一下輸入和輸出,並提供一類彼此(控制器)進行通信。您可以在控制器將數據提供給應用程序邏輯,得到的結果與在GUI一樣顯示出來:

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

你的組件應該鬆耦合,這樣你就可以重複使用並進行測試。你可以做到這一點簡單的依賴注入就像把你的依賴在contructors/setter方法:

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

這是非常簡單的控制器initializning法草案。有了這個,你可以在單元測試等其他地方測試/重用你的邏輯或你的GUI。

從你的窗口,所有的事件被觸發(按鈕等),移動經營業務邏輯,你可以創建一個接口,可以使你的窗口工作:

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

而且你可以在實現這個邏輯你CONTROLER(implements),並把它作爲GUI事件接收器:

window.setProcessingController(controller); 

...

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

現在,您可以與窗口和控制器進行雙向通信。

這些都是基本要點,它使您具有可測試性並能夠根據需要製作儘可能多的邏輯/控制器/窗口。此外,您還有鬆耦合的組件:您可以注入一個幾乎爲空的AppLogic用於測試目的的存根或僞造的AppWindow來模擬用戶在測試中的行爲。當然,以替補多組件,則應提取interfeces和提供特定的實施方式中:

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

當然,你可以甚至進一步把它分解到單獨的數據訪問和bussines邏輯

而這所有的GUI操作(事件更新)應該在Swing事件線程中運行,所以你應該使用SwingUtils,怎麼一回事,因爲Swing不是線程安全的 remeber:

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

Remeber不硬在您的邏輯類中使用new代碼對象實例化,例如,不要在您的控制器中創建new Windownew ApplicationDataModel--因爲您無法獨立測試您的控制器或者在不同的邏輯/窗口實現中重複使用它 - 您只能創建一些類來準備你的應用程序依賴關係(創建組件並鏈接它們)和「啓動它」 - 通常是這樣稱爲工廠

如果你的邏輯將成長並變得更加複雜,將它分成多個服務對象,你可以使用一個命令模式產生的命令在圖形用戶界面和應用程序服務處理它(例如,在線程安全的隊列) - 這也是撤銷/重做能力的好起點。最後一件事 - 如果你有任何長時間運行的處理任務(即使它花了1秒鐘,我們可以說它長時間運行),記住直接調用它或在swingUtils中會凍結你的gui,所以對於長時間操作用Thread,Executors,Runnable,SwingWorker或其他東西(你可以使用觀察者模式來監視進程等)分離線程。

請記住,這是一個真正的大問題,本文只提到一些小的一般性建議。

要採取的「其他道路」可以使用已提供的體系結構來創建GUI應用程序,如Eclipse RCP或Netbeans Platform。

+0

哇,首先,感謝這個非常詳細的答案。你提出了很多我也一直在想的觀點。有一點讓我感到困惑的是,如果我想分離GUI和邏輯,我必須編寫大量樣板代碼。因此,例如,我需要爲每個TextField單獨設置「getter/setter」。這感覺非常多餘,或者我錯過了什麼? – cete3

+0

您可以從模型中傳輸「DTO」 - 數據傳輸對象以供控制器查看,這些數據將包含一些數據重複表示(若干文本顯示等)。並傳遞這個單個對象。你也可以將你的數據映射到你的gui,它可以直接訪問你的數據模型,並聽取更改/刷新事件並更新你的gui(參見像DefaultModel,DefaultTableModel這樣的實現的ListModel,TableModel等swing模型 - 這樣的例子本身存儲數據,但你可以在模型中查找數據 –

+0

也可以在這樣的模型中進行查找時,可以在向模型請求數據時創建一個線程安全的「狀態副本」,這樣可以防止在數據發生變化時顯示不確定數據的錯誤所以在需求或數據改變事件時,這種映射模型從模型請求數據的當前狀態,將其緩存(以防止修改和不合理)並更新gui組件。 –