cet*_*te3 2 java user-interface swing design-patterns
我编写了一个使用Swing进行GUI的应用程序,通过GUI接受文件,解析输入,保存DataList并将其发送到服务器.我关心我的程序的整个设计,我认为这不是很好.我正在使用Netbeans来设计GUI,并且有一个MainClass启动该GUI 的类,并且具有对GUI的静态引用.还有一些ExecClasses做上述解析和发送数据.
+----------------------+
| 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);
}
Run Code Online (Sandbox Code Playgroud)
我正在使用这些引用,以便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());
}
Run Code Online (Sandbox Code Playgroud)
我知道这远非伟大的设计,并没有遵循一些良好的实践指南,例如MVC.所以我的问题是:你如何设计这个以及你可以给我哪些一般指示?
首先,不要在事物上做静态引用的逻辑,可以在多个上下文中使用.例如,将来,您可以要求GUI界面的多个窗口与您的多个服务实例交互.
你也在扼杀可测试性.
分别处理GUI和应用程序逻辑 - 不要在应用程序逻辑(exec类)中考虑GUI文本字段等.只需考虑输入和输出,并提供一个相互通信的类(控制器).您可以向控制器中的应用程序逻辑提供数据,获取结果并在GUI中显示,如:
public void processFile( SomeInputFromGui input ) {
SomeResult result = applicationLogicObject.process( input );
guiObject.showResult( result );
}
Run Code Online (Sandbox Code Playgroud)
您的组件应该是松散耦合的,因此您可以重用并测试它们.您可以通过简单的依赖注入实现这一点,例如将依赖项放在contructors/setter中:
public void initApplication() {
AppLogic logic = new AppLogic();
AppWindow window = new AppWindow();
AppController controller = new Controller( logic , window );
}
Run Code Online (Sandbox Code Playgroud)
这是控制器初始化方法的非常简单的草案.有了它,您可以在其他地方测试/重用您的逻辑或GUI,如单元测试.
要从窗口中移动业务逻辑,触发所有事件(按钮等),您可以创建一个适用于您的窗口的界面:
public interface ProcessingController {
public void processFile( File x );
public void checkIntegrity();
public SomeDataValues getCurrentDataValues();
}
Run Code Online (Sandbox Code Playgroud)
您可以在controler(implements)中实现此逻辑,并将其用作GUI事件接收器:
window.setProcessingController( controller );
Run Code Online (Sandbox Code Playgroud)
...
private void ButtonActionPerformed(java.awt.event.ActionEvent evt) {
processingController.processText( jMyTextField.getText() );
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以与窗口和控制器进行双向通信.
这些是基本要点,它们为您提供了可测试性和能力,可以根据需要制作尽可能多的逻辑/控制器/窗口.此外,您还有松耦合组件:您可以为测试目的注入几乎空的AppLogic存根,或者伪造AppWindow以模拟测试中的用户操作.当然要替换组件,您应该提取干扰并提供特定的实现:
SwingAppWindow implements ApplicationUserInterface { ...
SQLDataManager implements ApplicationDataLogic { ...
BasicController implements ProcessingController { ...
Run Code Online (Sandbox Code Playgroud)
当然,您可以进一步拆分它以分离数据访问和bussines逻辑.
并记住你所有的gui动作(事件,更新)应该在swing事件线程中运行,所以你应该使用SwingUtils,因为swing不是线程安全的:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
.... queued action that changes the gui ...
}
});
Run Code Online (Sandbox Code Playgroud)
Remeber与不硬编码对象instantation new在你的逻辑类,例如不要让new Window并new ApplicationDataModel在您的控制器-因为你不能independly测试你的控制器或者与不同的逻辑/窗口实现重用-你只能创建一些类准备你的应用程序依赖项(创建组件并链接它们)和"启动它" - 它通常被称为工厂.
如果您的逻辑将变得更加复杂,请将其拆分为更多服务对象,您可以使用命令模式在gui中生成命令并在应用程序服务中处理它(例如在线程安全队列中) - 这也将是一个好的开始指向撤消/重做能力.
最后一件事 - 如果你有任何长时间运行的处理任务(即使花了1秒我们可以说它已经运行很长时间),记住直接调用它或在swingUtils中会冻结你的gui,所以对于lenghty操作创建单独的线程Thread,Executors,Runnable,SwingWorker等(你可以使用观察者模式监视进度等).
请记住,这确实是一个很大的话题,本文仅提及一些小的一般性建议.
要采取的"其他方法"可以是使用已经提供的架构来创建Eclipse RCP或Netbeans Platform等GUI应用程序.