Java - OOP 和 MVC

标签 java swing oop model-view-controller

很难说出这里问的是什么。这个问题是模棱两可的、模糊的、不完整的、过于宽泛的或修辞的,无法以目前的形式得到合理的回答。如需帮助澄清这个问题以便重新打开它,visit the help center .




8年前关闭。




我试图了解如何在我的 Java 应用程序中实现 MVC,阅读一些教程和 MVC hello worlds,但我仍然不确定很多事情,所以如果你能帮助我理解这一切,我会很高兴。

假设我有一个简单的 GUI 应用程序,用于存储和处理各种建筑物。我可以通过从列表中选择类型并按下按钮来添加建筑物。这些建筑物将存储在一些数组列表中,显示在 GUI 中并且可以编辑(房间数,楼层数......不重要)。建筑物将显示在 JComboBox 中,选择某个建筑物后,将出现该建筑物的设置面板。

到目前为止,我有 2 个“组件”。 建筑物 (容器)和建筑 .我创建了 建筑模型 持有建筑物的类有一些方法可以与它们一起工作,并在更改后通知观察者。然后我有一个 建筑物查看 类,它正在观察 BuildingsModel。然后我有 建筑物 Controller 仅具有构造函数方法的类,它将 BuildingsModel 和 BuildingsView 作为参数,将 View 绑定(bind)到模型作为观察者,创建一些初始建筑物并向 View 添加一些监听器。

现在我不知道如何继续。有几件事情我不是很高兴。

  • 我已将监听器绑定(bind)到按钮,它将从 View 中的 JList 中获取当前选择,创建新对象(xxxBuildingModel)并将其添加到 BuildingsModel。然而,JList 只包含所有建筑类型的字符串表示,为了避免长的 if-else 语句并为该字符串找到正确的类,我不得不使用反射。 (每种建筑类型都有自己的扩展类 BuildingModel 。)有没有更好的方法呢?
  • 第二个监听器绑定(bind)到包含已创建的构建实例的 JComboBox。在该组合框中选择建筑物后,我想显示该建筑物的设置表单。所以我想应该有一些与 BuildingModel 关联的 View 类,它将显示其当前设置(模型的状态)。但我不确定,如何从 BuildingsController 的构造函数上下文中做到这一点。我只能访问建筑物的模型,那么我应该如何“找到”该实例的正确 View 并显示它?也许我做错了,组合框不应该只包含模型而是 Controller (可以访问模型和 View ),在这种情况下,我可以调用 Controller 的 View 方法,该方法将从模型中获取所需的数据,传递它以查看和显示它。如果我应该使用具体的建筑实例作为模型、 Controller 或封装所有这 3 个组件( Controller 、模型、 View )的自定义类,我不会...

  • 这是代码中最重要的部分。我没有包括 BuildingModel 类及其子类,因为现在它们只是带有 toString() 方法的空白类。
        public class BuildingsController {
            public BuildingsController(final BuildingsModel model, final BuildingsView view) {
                class addBuildingButtonActionListener implements ActionListener {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        String selectedBuildingType;
                        if ((selectedBuildingType = view.getSelectedBuildingType()) != null) {
                            try {
                                BuildingModel newBuilding = (BuildingModel) Class.forName("building.models." + selectedBuildingType + "BuildingModel").newInstance();
                                model.addBuilding(newBuilding);
    
                            } catch (InstantiationException ex) {
                                //addToErrorLog
                            } catch (IllegalAccessException ex) {
                                //addToErrorLog
                            } catch (ClassNotFoundException ex) {
                                //addToErrorLog
                            }
                        } else {
                            //addToLog - NO_BUILDING_SELECTED
                        }
                    }
                }
    
                class buildingComboBoxSelectListener implements ActionListener {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        BuildingModel selectedBuilding;
                        if ((selectedBuilding = view.getSelectedBuilding()) != null) {
                            //display current building form???
                        }
                    }
                }
                model.addObserver(view);
                model.addBuilding(new HospitalBuildingModel());
                model.addBuilding(new SchoolBuildingModel());
    
                view.fillBuildingTypesList(BuildingsModel.getAllBuildingsTypes());
                view.addAddBuildingButtonListener(new addBuildingButtonActionListener());
                view.addActiveBuildingsListener(new buildingComboBoxSelectListener());
            }
        }
        public class BuildingsModel extends Observable {
            private static String[] allBuildingsTypes = {"School", "Hospital", "Stadion"};
            private ArrayList<BuildingModel> buildings = new ArrayList<BuildingModel>();
    
            public void addBuilding(BuildingModel building){
                this.buildings.add(building);
                this.setChanged();
                this.notifyObservers();
            }
            public BuildingModel[] getAllBuildings(){
                return this.buildings.toArray(new BuildingModel[this.buildings.size()]);
            }
            public static String[] getAllBuildingsTypes(){
                return BuildingsModel.allBuildingsTypes;
            }
    
        }
        public class BuildingsView implements Observer {
            private static String name = "Buldings";
            private static String addBuildingButtonText = "Add building";
            private JComboBox allActiveBuildings = new JComboBox();
            private JList buildingTypesList = new JList();
            private JButton addBuildingButton = new JButton(BuildingsView.addBuildingButtonText);
    
    
            @Override
            public void update(Observable model, Object o){
                BuildingModel[] allBuildings = ((BuildingsModel) model).getAllBuildings();
                this.allActiveBuildings.removeAllItems();
                for(BuildingModel building : allBuildings){
                    this.allActiveBuildings.addItem(building);
                }
            }
            public String getSelectedBuildingType(){
                return (String) this.buildingTypesList.getSelectedValue();
            }
            public BuildingModel getSelectedBuilding(){
                return (BuildingModel) this.allActiveBuildings.getSelectedItem();
            }
    
            public void fillBuildingTypesList(String[] buildingTypes){
                this.buildingTypesList.setListData(buildingTypes);
            }
    
            public void addAddBuildingButtonListener(ActionListener l){
                this.addBuildingButton.addActionListener(l);
            }
            public void addActiveBuildingsListener(ActionListener l){
                this.allActiveBuildings.addActionListener(l);
            }
            public JComponent display(){
                JPanel panel = new JPanel();
                Border border = BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(BuildingsView.name), BorderFactory.createEmptyBorder(5, 5, 5, 5));
                panel.setBorder(border);
                panel.add(this.allActiveBuildings);
                panel.add(this.buildingTypesList);
                panel.add(this.addBuildingButton);
    
                panel.setPreferredSize(new Dimension(200, 262));
    
                return panel;
            }
        }
    

    主要:
        public static void main(String[] args) {
            BuildingsView buildingsView = new BuildingsView();
            BuildingsModel buildingsModel = new BuildingsModel();
            BuildingsController buldingsController = new BuildingsController(buildingsModel, buildingsView);
    
    
            mainWindow window = new mainWindow("MVC test", buildingsView);
            window.generateDefaultLayout();
            window.showMainWindow();
    
        }
    

    窗口:
    public class mainWindow extends JFrame {
        private JPanel buildingsPanel = new JPanel();
        private BuildingsView buildingsView;
    
        public mainWindow(String title, BuildingsView buildingsView) {
            this.buildingsView = buildingsView;
            this.setTitle(title);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
        public void generateDefaultLayout(){
            this.setLayout(new FlowLayout());
            this.setPreferredSize(new Dimension(1200, 920));
            this.addBuildingsPanel();
        }
        public void addBuildingsPanel(){
            this.buildingsPanel.add(this.buildingsView.display());
            this.add(this.buildingsPanel);
        }
        public void showMainWindow(){
            this.pack();
            this.setVisible(true);
        }
    }
    

    谢谢 :)

    最佳答案

    I have binded listener to the button, that will get the current selection from JList in view, create new object (xxxBuildingModel) and add it to BuildingsModel. However, the JList contains just String representations of all building types and to avoid long if-else statemenets and finding the right class for that String, I had to use reflection. (Each building type has its own class that extends BuildingModel.) Is there any better way to do it?



    是的。不要让您的 JList 保存字符串,而是让它保存建筑(非 GUI)对象。使用 ListCellRenderer 告诉 JList 如何最好地显示每个建筑物。然后,当用户从 JList 中选择一个项目时,他们选择的是一个实际的建筑对象,而不是它的字符串表示形式。当然,不要考虑对此进行反射(reflection)。

    The second listener is bound to JComboBox that contains already created building instances. After selecting building in that combobox, I want to display settings form for that building. So I guess there should be some view class associated with BuildingModel that will display its current settings (model's state). But I am not sure, how to do it from the BuildingsController's constructor context.



    您可以在 Control 类中有一个 AbstractAction 类并将其用作 JComboBox 的监听器(有关此问题的更多信息,请参见我对上一个问题 here 的回答)。

    I have access only to building's model, so how should I "find" the right view for that instance and display it?



    您将从监听器中获取选定的建筑物,然后监听器将通过调用 View 上的公共(public)方法来通知 GUI 在选择后更改 View 。

    Maybe I am doing it all wrong and the combobox shouldn't contain just models but controllers (which has access to both model and view),



    组合框的监听器将成为控件的一部分,是的。这将可以访问模型和 View 。

    in that case I could just call the controller's view method, which will get the needed data from model, passes it to view and display it.



    我不确定您的程序本身的细节是否能够回答这个问题。

    编辑 1
    在查看您的代码时,我发现了一个潜在问题:
        private static String[] allBuildingsTypes = {"School", "Hospital", 
                "Stadion"};
        private ArrayList<BuildingModel> buildings = new ArrayList<BuildingModel>();
    

    您不应该在此处使用字符串,而应该使用行为良好的面向对象的 Building 类,该类具有名称 String,以及在您的 Building 对象需要的任何属性中重要的所有其他属性。然后你的模型应该处理建筑物对象的集合而不是建筑物的字符串表示。您的 View 将显示这些建筑物的属性,并允许用户能够更新您允许他们更改的属性。

    这涉及您程序结构的核心,因此我觉得非常重要,这样做可能需要您更改所有内容,但从长远来看,这将是非常值得的。

    编辑 1b : 我的立场是正确的。看起来您有一个用于此的类 BuildingModel,其代码尚未在此处发布。我想知道您的 BuildingTypes 是否应该是属于您的 BuildingModel 类的枚举。

    编辑 2
    有关更多 Swing-MVC 相关代码的答案,请查看以下链接:
  • Using a JFileChooser with Swing GUI classes and listeners :我创建的一个小型 Swing MVC 示例。
  • GUI not working after rewriting to MVC : 我对垃圾神的例子赞不绝口。您不应该阅读它,而应该研究它。
  • JAVA Swing MVC - Main Controller?
  • 关于Java - OOP 和 MVC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16448194/

    相关文章:

    c++ - 如何设计具有不同类型的通知和观察者的观察者模式?

    java - Jaxws 不填充结果

    java - Android Studio 类名绿色?

    java - jpanel 与其他组件重叠

    java - Java Swing 中模型组件的多个实例?

    java - 手动鼠标拖动调整包含 JScrollPane 的 JOptionPanel 的大小

    java - 如何使用 hibernate 在 java 中正确实现 owner-owned-owner2 关联?

    java - Xpath 无法查询带有命名空间的标签

    oop - 如何将单一职责原则应用于服务类

    java - 设计具有枚举依赖性的类的最佳方法