什么';在MVC架构中公开Java组件(如JButton)的最佳方式是什么?

什么';在MVC架构中公开Java组件(如JButton)的最佳方式是什么?,java,swing,model-view-controller,private,public,Java,Swing,Model View Controller,Private,Public,我目前正在用Java编程一个21点应用程序,它需要用MVC架构编写。我有我所有的模型,视图和控制器完全编码,一切工作完美。但是,我想知道将侦听器附加到组件的最佳方式是什么(例如,JButton) 我当前的设计声明了视图中所有需要侦听器作为公共final的组件。然后,它将视图传递给控制器。从那里,控制器可以完全访问组件并添加操作侦听器。代码示例: public class View extends JFrame { public final JButton myBtn1 = new JBu

我目前正在用Java编程一个21点应用程序,它需要用MVC架构编写。我有我所有的模型,视图和控制器完全编码,一切工作完美。但是,我想知道将侦听器附加到组件的最佳方式是什么(例如,JButton)

我当前的设计声明了视图中所有需要侦听器作为公共final的组件。然后,它将视图传递给控制器。从那里,控制器可以完全访问组件并添加操作侦听器。代码示例:

public class View extends JFrame {
    public final JButton myBtn1 = new JButton("Button 1");
    public final JButton myBtn2 = new JButton("Button 2");

    public View() {
        //constructor code here....
    }
}

public class Controller {
    private Model myModel;
    private View myView;

    public Controller(Model m, View v) {
        myModel = m;
        myView = v;

        //now add listeners to components...

        myView.myBtn1.addActionListener(new MyActionListener1());
        myView.myBtn2.addActionListener(new MyActionListener2());
    }
}
public class View extends JFrame {
    private JButton myBtn1 = new JButton("Button 1");
    private JButton myBtn2 = new JButton("Button 2");

    public View() {
        //constructor code here....
    }

    public void myBtn1AddActionListener(ActionListener a) {
        myBtn1.addActionListener(a);
    }

    public void myBtn2AddActionListener(ActionListener a) {
        myBtn2.addActionListener(a);
    }

    //etc etc...
}

public class Controller {
    private Model myModel;
    private View myView;

    public Controller(Model m, View v) {
        myModel = m;
        myView = v;

        //now add listeners to components...

        myView.myBtn1AddActionListener(new MyActionListener1());
        myView.myBtn2AddActionListener(new MyActionListener2());
    }
}
然而,我的一个朋友已经用私有范围声明了他的所有JButton,然后在视图中公开了方法,以便将动作侦听器添加到它们各自的组件中。对我来说,这简直是浪费时间,只会添加不必要的代码。代码示例:

public class View extends JFrame {
    public final JButton myBtn1 = new JButton("Button 1");
    public final JButton myBtn2 = new JButton("Button 2");

    public View() {
        //constructor code here....
    }
}

public class Controller {
    private Model myModel;
    private View myView;

    public Controller(Model m, View v) {
        myModel = m;
        myView = v;

        //now add listeners to components...

        myView.myBtn1.addActionListener(new MyActionListener1());
        myView.myBtn2.addActionListener(new MyActionListener2());
    }
}
public class View extends JFrame {
    private JButton myBtn1 = new JButton("Button 1");
    private JButton myBtn2 = new JButton("Button 2");

    public View() {
        //constructor code here....
    }

    public void myBtn1AddActionListener(ActionListener a) {
        myBtn1.addActionListener(a);
    }

    public void myBtn2AddActionListener(ActionListener a) {
        myBtn2.addActionListener(a);
    }

    //etc etc...
}

public class Controller {
    private Model myModel;
    private View myView;

    public Controller(Model m, View v) {
        myModel = m;
        myView = v;

        //now add listeners to components...

        myView.myBtn1AddActionListener(new MyActionListener1());
        myView.myBtn2AddActionListener(new MyActionListener2());
    }
}
那么,考虑到上述两种情况,哪种方法更好


谢谢。

如果您的问题与架构API(目前不是真正的API)有关,那么我认为这两种方法都不好,而且在您没有真正的经验和清楚地理解它之前,不要使用任何模式,因为结果将不好

我当前的设计声明了视图中所有需要侦听器作为公共final的组件。然后,它将视图传递给控制器。从那里,控制器可以完全访问组件并添加操作侦听器。代码示例:

public class View extends JFrame {
    public final JButton myBtn1 = new JButton("Button 1");
    public final JButton myBtn2 = new JButton("Button 2");

    public View() {
        //constructor code here....
    }
}

public class Controller {
    private Model myModel;
    private View myView;

    public Controller(Model m, View v) {
        myModel = m;
        myView = v;

        //now add listeners to components...

        myView.myBtn1.addActionListener(new MyActionListener1());
        myView.myBtn2.addActionListener(new MyActionListener2());
    }
}
public class View extends JFrame {
    private JButton myBtn1 = new JButton("Button 1");
    private JButton myBtn2 = new JButton("Button 2");

    public View() {
        //constructor code here....
    }

    public void myBtn1AddActionListener(ActionListener a) {
        myBtn1.addActionListener(a);
    }

    public void myBtn2AddActionListener(ActionListener a) {
        myBtn2.addActionListener(a);
    }

    //etc etc...
}

public class Controller {
    private Model myModel;
    private View myView;

    public Controller(Model m, View v) {
        myModel = m;
        myView = v;

        //now add listeners to components...

        myView.myBtn1AddActionListener(new MyActionListener1());
        myView.myBtn2AddActionListener(new MyActionListener2());
    }
}
不,不要不必要地公开字段——不应该为了MVC而牺牲封装。您不应出于上述原因公开组件。而是提供控件可以调用的视图公共方法,或者让视图通过模型的侦听器更改状态。将控件传递给视图,将视图传递给控件,所有交互都应该通过公共方法进行,而不是通过公开组件或字段

我解决这个问题的一种方法,并不是说这是最好的或规范的方法,就是将控件的实例传递到视图中,为我的侦听器使用匿名内部类,并让这些类调用控件方法。那么比如说,

// inside of view
exitButton.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent evt) {
      if (control != null) {
         control.exitAction();
      }
   }
});

虽然我个人喜欢你的风格,但你会发现你朋友的风格(或类似风格)更像“标准Java风格”。因此,在一个典型的编程团队中,它将更容易被接受。它还有一个(可能的)优点(和可能的缺陷),即在某些使用情况下,按钮可以被不同的按钮替换。

注意:这个答案是我个人的意见。我仍然需要找到关于编写Swing UI的“最佳/最推荐”方法的详细资料,并将其与业务逻辑联系起来。但在我找到答案之前,我会运用常识和个人经验

我想说,两者都不是实现这一目标的正确方法。在MVC中,视图只是向用户提供视觉信息的部分。但是,当您按下按钮时,在
ActionListener
中触发的代码属于控制器中的代码,因为它很可能是业务逻辑(这是我根据您的代码片段所做的假设。如果您的按钮只是执行一个UI操作,比如启用另一个组件,那么该操作侦听器应该完全包含在视图中)

因此,我会在控制器中公开这些方法,例如,如果您当前有一个
ActionListener
之类的

public void actionPerformed( ActionEvent e ){
  doSomeStuff( UI info, event info );
}
如果
UI info
是从视图获得的信息,而
event info
是从事件获得的信息,我将在控制器上介绍public方法

public void doSomeStuff( UI info, event info )
并从视图调用该方法。这有两个主要好处:

  • 只有从视图到控制器的依赖关系,而不是从控制器到视图的依赖关系。如果控制器包含业务逻辑,则不太可能在SwingUI中重复使用该代码。这里不需要依赖Swing类。例如,可以进行单元测试。如果您的控制器没有在UI上,您可以轻松地测试应用程序的控制器模型部分,并通过使用API遵循与通过UI调用这些调用相同的代码路径
  • 您可以完全调整UI,并决定用另一个组件替换按钮,而不必重写控制器和视图,就无法将
    ActionListener
    附加到该组件
  • 编辑

    尽管我认为我的文章的上述部分仍然有效,但我必须承认,在阅读了垃圾神的回答(他在一篇评论中提到)中提到的内容后,上述内容只是对MVC模式以及如何在Swing应用程序中实现MVC模式的一种解释

    查看该Wiki页面,它将MVC中的三个组件定义为(总结):

    • 模型:管理应用程序域的行为和数据
    • 视图:将模型渲染为适合交互的形式,通常是用户界面元素
    • 控制器:接收用户输入并通过调用模型对象启动响应
    我的解释/观点/首选方法是使用一个模型和一个控制器,如果需要,使用多个视图(或例如在测试零视图时)。控制器不直接接收用户输入(这相当于让它在视图上注册侦听器),但提供API钩子将用户输入传递到。这提供了一种“抽象控制器”,可以处理用户输入,但视图仍需要将真实的用户输入事件转换为控制器可以理解的事件/信息。因此,这意味着我可以轻松创建MVC的测试“视图”端以及真实的“视图”端无需更改控制器或模型中的任何内容

    另一种解释是在控制器和视图之间有一个更紧密的耦合(它们实际上相互依赖)。这也意味着如果您决定从