A Model View Controller szavakból alkotott betűszó. A szoftverfejlesztésben használatos szerkezeti minta. Azt jelenti, szétválasztjuk a megjelenésérét felelős kódrészeket, az adatokért és a vezérlésért felelős kódrészektől.
A következő példában egyetlen állományban valósítjuk meg az MVC-t. A View név helyett a MainWindow nevet használom osztálynévnek. De lehetne akár View osztály is.
import javax.swing.JFrame; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JTextField; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.FlowLayout; class MainWindow extends JFrame { private JButton calcButton = new JButton("Számít"); public JTextField baseField = new JTextField(10); public JTextField heightField = new JTextField(10); public JTextField resultField = new JTextField(10); private JLabel baseLabel = new JLabel("alap:"); private JLabel heightLabel = new JLabel("magasság:"); MainWindow() { resultField.setVisible(false); add(baseLabel); add(baseField); add(heightLabel); add(heightField); add(resultField); add(calcButton); setLayout(new FlowLayout()); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); centerWindow(this); setVisible(true); } public void addCalcButtonActionListener(ActionListener listener) { calcButton.addActionListener(listener); } public static void centerWindow(java.awt.Window frame) { java.awt.Dimension dimension = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); int x = (int)((dimension.getWidth() - frame.getWidth()) / 2); int y = (int)((dimension.getHeight() - frame.getHeight()) / 2); frame.setLocation(x, y); } } class Controller { MainWindow mainWindow = new MainWindow(); Model model = new Model(); Controller() { mainWindow.addCalcButtonActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event) { String baseStr = mainWindow.baseField.getText(); String heightStr = mainWindow.heightField.getText(); double base = Double.parseDouble(baseStr); double height = Double.parseDouble(heightStr); Double area = model.calcArea(base, height); mainWindow.resultField.setText(area.toString()); mainWindow.resultField.setVisible(true); mainWindow.pack(); } }); } } class Model { public double calcArea(double base, double height) { if(base <= 0 || height <=0) { throw new IllegalArgumentException(); } return (base * height) /2; } } class Program01 { public static void main(String[]args) { new Controller(); } }
Nagyobb projektekben a modell, nézet és kontroller számára is külön könyvtárat késztünk.
A következő könyvtárszerkezetet alakítjuk ki:
projektKonyvtar/ |--views/ | `--MainFrame.java |--models/ | `--Model.java |--controllers/ | `--Controller.java |--Makefile `--Haromszog.java
package view; import javax.swing.JFrame; public class MainFrame extends JFrame { public MainFrame() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 300); setVisible(true); } }
package model; public class Model { }
package controller; import view.MainFrame; import model.Model; public class Controller { MainFrame mainFrame = new MainFrame(); Model model = new Model(); public Controller() { } }
import controller.Controller; class Haromszog { public static void main(String[] args) { new Controller(); } }
SOURCE=view/MainFrame.java \ model/Model.java \ controller/Controller.java \ Haromszog.java all: javac -cp . $(SOURCE) run: xterm -e "java -cp . Haromszog; read"
A következőben a háromszög területszámító program komplett megvalósítását látjuk, egységteszttel együtt. Tesztelni csak a model részt teszteljük, ahol maga a számítás történik.
projektKonyvtar/ |--views/ | `--MainFrame.java |--models/ | `--Model.java |--controllers/ | `--Controller.java |--Makefile |--Haromszog.java `--test/ `--ModelTest.java
package view; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.JButton; import javax.swing.BoxLayout; import javax.swing.JPanel; import java.awt.FlowLayout; import java.awt.event.ActionListener; public class MainFrame extends JFrame { JPanel topPanel = new JPanel(); JLabel titleLabel = new JLabel("Háromszög területszámító"); JPanel bottomPanel = new JPanel(); JLabel baseLabel = new JLabel("alap:"); public JTextField baseField = new JTextField(5); JLabel heightLabel = new JLabel("magasság:"); public JTextField heightField = new JTextField(5); public JLabel resultLabel = new JLabel("eredmény:"); public JTextField resultField = new JTextField(5); JButton calcButton = new JButton("Számít"); public MainFrame() { topPanel.setLayout(new FlowLayout()); topPanel.add(titleLabel); bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.X_AXIS)); bottomPanel.add(baseLabel); bottomPanel.add(baseField); bottomPanel.add(heightLabel); bottomPanel.add(heightField); bottomPanel.add(resultLabel); bottomPanel.add(resultField); bottomPanel.add(calcButton); resultLabel.setVisible(false); resultField.setVisible(false); setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); add(topPanel); add(bottomPanel); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); setVisible(true); } public void addCalcButtonActionListener(ActionListener listener) { calcButton.addActionListener(listener); } }
package test; import org.junit.Test; import static org.junit.Assert.*; import model.Model; public class ModelTest { Model model = new Model(); @Test public void testCalcArea() { assertEquals(525, model.calcArea(30, 35), 0); assertEquals(900, model.calcArea(40, 45), 0); } @Test(expected = IllegalArgumentException.class) public void tesztExceptionSzamitTerulet() { model.calcArea(0, 35); } }
package model; public class Model { public static double calcArea(double base, double height) { if (base <= 0 || height <= 0) { throw new IllegalArgumentException("Nem megfelelő paraméterek"); } return (base * height) / 2; } }
package controller; import view.MainFrame; import model.Model; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; public class Controller { MainFrame mainFrame = new MainFrame(); Model model = new Model(); public Controller() { mainFrame.addCalcButtonActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event) { String baseStr = mainFrame.baseField.getText(); double base = Double.parseDouble(baseStr); String heightStr = mainFrame.heightField.getText(); double height = Double.parseDouble(heightStr); Double result = model.calcArea(base, height); mainFrame.resultField.setText(result.toString()); mainFrame.resultField.setVisible(true); mainFrame.resultLabel.setVisible(true); mainFrame.pack(); } }); } }
import controller.Controller; class Haromszog { public static void main(String[] args) { new Controller(); } }
SOURCE=view/MainFrame.java \ model/Model.java \ controller/Controller.java \ Haromszog.java all: javac -cp . $(SOURCE) run: xterm -e "java -cp . Haromszog; read" LINJUNIT=/usr/share/java/junit4.jar testl: javac -cp .:$(LINJUNIT) test/ModelTest.java java -cp .:$(LINJUNIT) org.junit.runner.JUnitCore test.ModelTest WINJUNIT=c:\bin\SWScite\javalibs\junit-4.11.jar WINHAMCREST=c:\bin\SWScite\javalibs\hamcrest-core-1.3.jar testw: javac -cp .;$(WINJUNIT);$(WINHAMCREST) test/ModelTest.java java -cp .;$(WINJUNIT);$(HAMCREST) org.junit.runner.JUnitCore test.ModelTest
package view; import controller.Controller; public class Mainwindow extends javax.swing.JFrame { Controller controller = new Controller(this); public Mainwindow() { initComponents(); } //... private void aboutButtonActionPerformed(java.awt.event.ActionEvent evt) { controller.aboutButtonActionListener(evt); } public static void main(String args[]) { //... } //.. private javax.swing.JButton aboutButton; }
package controller; import java.awt.event.ActionEvent; import javax.swing.JFrame; import javax.swing.JOptionPane; import model.Model; public class Controller { Model model = new Model(); Mainwindow jframe; public Controller(Mainwindow jframe) { this.jframe = jframe; } public void aboutButtonActionListener(ActionEvent ev ) { JOptionPane.showMessageDialog(jframe, "Működik"); } }
package model; public class Model { }
app01/ |-lib/ `-src/ |-controllers/ | `-MainController.java |-models/ | `-MainModel.java |-views/ | `-MainFrame.java `-App.java
import controllers.MainController; public class App { public static void main(String[] args) throws Exception { new MainController(); } }
package views; import javax.swing.JFrame; public class MainFrame extends JFrame { public MainFrame() { this.setTitle("App"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(400, 300); this.setVisible(true); } }
package models; public class MainModel { }
package controllers; import models.MainModel; import views.MainFrame; public class MainController { MainFrame mainFrame; MainModel mainModel; public MainController() { this.mainFrame = new MainFrame(); this.mainModel = new MainModel(); } }