3 Swing应用程序设计:哪个最好?

use*_*466 15 java architecture model-view-controller swing

我是桌面应用程序开发的新手,今年夏天我有一个非常大的项目.问题是代码必须非常清晰,所以当我更新代码时,我不会遇到麻烦.

结果,我想要一个良好的"关注点分离".对我来说最困难的部分是视图 - 控制器分离.

现在,我已经阅读了很多教程,讨论等.我已经以3种不同的方式设计了一个迷你应用程序.该应用程序很简单:单击将标签转换为"Hello world"的按钮.

你怎么看待这3个设计?

有没有更好的设计来满足我的期望?

设计1

View1.java:

public View1() {
    initComponents();
    this.controller = new Controller1(this);
}

private Controller1 controller;

public void updateLabel(String message){
    this.jLabel1.setText(message);
}

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
    this.controller.doSomething();
}

private void initComponents() {
...
jButton1.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jButton1ActionPerformed(evt);
        }
    });
...}
Run Code Online (Sandbox Code Playgroud)

Controller1.java:

public class Controller1 {
    public Controller1(View1 v){
        this.view = v;
    }

    public void doSomething(){
        this.view.updateLabel("Hello world");
    }

    private View1 view;
}
Run Code Online (Sandbox Code Playgroud)

设计2

View2.java:

public View2() {
        initComponents();
        this.controller = new Controller2(this);

        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                controller.doSomething();
            }
        });
    }
    public void updateLabel(String message){
        this.jLabel1.setText(message);
    }
    private Controller2 controller;
  ...
Run Code Online (Sandbox Code Playgroud)

}

Controller2.java:

public class Controller2 {

        public Controller2(View2 v){
            this.view = v;
        }

        public void doSomething(){
            this.view.updateLabel("Hello world");
        }

        private View2 view;
}
Run Code Online (Sandbox Code Playgroud)

设计3

View3.java:

public View3() {
        initComponents();
        this.controller = new Controller3(this);
        this.jButton1.addActionListener(this.controller.listener);
    }
    private Controller3 controller;
    public void updateLabel(String message){
        this.jLabel1.setText(message);
    }
...}
Run Code Online (Sandbox Code Playgroud)

Controller3.java:

public class Controller3 {

    public Controller3(View3 v){
        this.view = v;
        this.listener = new MyListener(v);
    }

    private View3 view;
    public MyListener listener;
}
Run Code Online (Sandbox Code Playgroud)

MyListener.java:

public class MyListener implements ActionListener{
    private View3 view;

    public MyListener(View3 v){
        this.view = v;
    }

    public void actionPerformed(java.awt.event.ActionEvent evt) {
                this.view.updateLabel("Hello world");
            }
}
Run Code Online (Sandbox Code Playgroud)

Ami*_*far 10

我不喜欢这些设计.您将控制器与视图紧密耦合.假设您希望将来更改控制器实现,因此您必须进入所有类并更改类.相反,你应该注入它.有很多lib可以通过GuiceSpring这样的注释为你做这些,但我不会去那些.这是一个更好的设计.

public class View{
private Controller controller;
   public View(Controller controller) {
       this.controller = controller;
   }
}
Run Code Online (Sandbox Code Playgroud)

这是一个更清洁的设计,因为视图不必知道控制器的实现是什么.您可以稍后创建一个子类并传递它.

所以现在通过上面的设计,我认为你可以看到你不应该将View传递给控制器​​.这又是耦合,这是不好的.相反,你可以传递一个onCallback类,它将在完成后执行.这是代码来代替它

jButton1.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
            controller.doSomething(new Runnable(){
                    public void run(){
                        updateLabel("Hello world");
                    }               
           });
       }
});
Run Code Online (Sandbox Code Playgroud)

然后在你的控制器做

public void doSomething(Runnable callback){
   // do work
   SwingUtilties.invokeLater(callback);
}
Run Code Online (Sandbox Code Playgroud)

如果你看起来我建议删除任何类型的耦合.该视图不应该要求控制器,应该给予它.Controller不应该知道应该只执行回调的视图.这很重要,因为如果您决定不使用Swing,那么您的控制器中的Swing包就不会具有所有这些依赖关系.

希望这一切都有帮助!!


Gar*_*all 6

确定哪种模式最佳取决于您正在解决的问题. Swing已经是一个MVC框架,因此您必须考虑在其上添加另一层间接是否值得付出努力.

由于您是UI编程的新手,我建议您先将系统的步骤框架放在一起,然后根据您从中学到的内容,决定您的架构.精心设计的架构使测试和重用组件变得容易. MVPMVVM是两种众所周知的UI设计模式.

对于你的玩具问题,你可以像我一样实现MVP或MVVM.请记住,您通常也会在每个接口之间使用接口,如果可以更改,则会在Model上有观察者.

MVP

public class Model {
    public String getWhatIWantToSay() {
        return "Hello World";
    }
}

public class Presenter implements ActionListener {
    private final View view;
    private final Model model;
    public Presenter(Model model, View view) {
        this.model = model;
        this.view = view;
        view.addButtonListener(this);
    }
    public void actionPerformed(ActionEvent e) {
        view.setText(model.getWhatIWantToSay());
    }
}

public class View {
    private JButton button = new JButton();
    private JLabel label = new JLabel();
    public void addButtonListener(ActionListener listener) {
        button.addActionListener(listener);
    }
    public void setText(String text) {
        label.setText(text);
    }
}
Run Code Online (Sandbox Code Playgroud)

MVVP

public class ModelView extends Observable {
    private final Model model;
    private String text = "";

    public ModelView(Model model) {
        this.model = model;
    }

    public void buttonClicked() {
        text = model.getWhatIWantToSay();
        notifyObservers();
    }
}

public class View implements Observer {
    private JButton button = new JButton();
    private JLabel label = new JLabel();
    private final ModelView modelView;

    public View(final ModelView modelView) {
        this.modelView = modelView;
        modelView.addObserver(this);
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                modelView.buttonClicked();
            }
        });
    }

    public void update(Observable o, Object arg) {
        label.setText(modelView.text);
    }
}
Run Code Online (Sandbox Code Playgroud)