Java/Design Pattern/MVC Pattern
Версия от 18:01, 31 мая 2010; (обсуждение)
MVC Implementation
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
* All rights reserved. Software written by Ian F. Darwin and others.
* $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS""
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
* cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
* pioneering role in inventing and promulgating (and standardizing) the Java
* language and environment is gratefully acknowledged.
*
* The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
* inventing predecessor languages C and C++ is also gratefully acknowledged.
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* MVC Implementation
*
* @author Ian Darwin, http://www.darwinsys.ru/
* @version $Id: MVCDemo.java,v 1.3 2004/03/21 00:44:36 ian Exp $
*/
public class MVCDemo {
/** "main program" method - construct and show */
public static void main(String[] av) {
// Create the data model
final Model model = new Model();
// create a JFrame to hold it all.
final JFrame f = new JFrame("MVC");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = f.getContentPane();
JPanel tp = new JPanel();
cp.add(tp, BorderLayout.NORTH);
tp.add(new JLabel("New value:"));
final JTextField tf = new JTextField(10);
tp.add(tf);
tf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
model.add(tf.getText());
tf.setText("");
}
});
JPanel p = new JPanel();
// The first View is a JTextArea subclassed to have
// an easy way of setting the data from a java.util.List
final TextView tv = new TextView();
model.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent evt) {
Object o = evt.getSource();
Model m = (Model) o;
tv.setListData(m.getData());
}
});
tv.setBackground(Color.RED);
tv.setSize(100, 100);
p.add(tv);
// The second View is the simplistic Grapher program from
// the Java Cookbook "Graphics" chapter (../graphics/Grapher.java)
final Grapher vv = new Grapher();
model.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent evt) {
Object o = evt.getSource();
Model m = (Model) o;
vv.setListData(m.getData());
}
});
vv.setBackground(Color.YELLOW);
vv.setSize(100, 100);
p.add(vv);
cp.add(p, BorderLayout.CENTER);
f.pack();
f.setLocation(100, 100);
f.setVisible(true);
}
}
class TextView extends JTextArea {
public TextView() {
super(20, 20);
}
public void setListData(ArrayList l) {
setText("");
for (int i = 0; i < l.size(); i++) {
append((String) l.get(i));
append("\n");
}
}
}
class Model {
private ArrayList list = new ArrayList();
public void add(String s) {
list.add(s);
fireChange();
}
public ArrayList getData() {
return list;
}
// Sun recommends using javax.swing.EventListenerList, but this is easier
ArrayList changeListeners = new ArrayList();
public void addChangeListener(ChangeListener cl) {
changeListeners.add(cl);
}
public void removeChangeListener(ChangeListener cl) {
changeListeners.remove(cl);
}
protected void fireChange() {
ChangeEvent evt = new ChangeEvent(this);
for (int i = 0; i < changeListeners.size(); i++) {
ChangeListener cl = (ChangeListener) changeListeners.get(i);
cl.stateChanged(evt);
}
}
}
class Grapher extends JPanel {
/** Multiplier for range to allow room for a border */
public final static double BORDERFACTOR = 1.1f;
/** The list of Point points. */
protected ArrayList data;
/** The minimum and maximum X values */
protected double minx = Integer.MAX_VALUE, maxx = Integer.MIN_VALUE;
/** The minimum and maximum Y values */
protected double miny = Integer.MAX_VALUE, maxy = Integer.MIN_VALUE;
/** The range of X and Y values */
protected double xrange, yrange;
public Grapher() {
data = new ArrayList();
figure();
}
/**
* Set the list data from a list of Strings, where the x coordinate is
* incremented automatically, and the y coordinate is made from the String
* in the list.
*/
public void setListDataFromYStrings(ArrayList newData) {
data.clear();
for (int i = 0; i < newData.size(); i++) {
Point2D p = new Point2D.Double();
p.setLocation(i, java.lang.Double.parseDouble((String) newData
.get(i)));
data.add(p);
}
figure();
}
/** Set the list from an existing List, as from GraphReader.read() */
public void setListData(ArrayList newData) {
data = newData;
figure();
}
/** Compute new data when list changes */
private void figure() {
// find min & max
for (int i = 0; i < data.size(); i++) {
Point2D d = (Point2D) data.get(i);
if (d.getX() < minx)
minx = d.getX();
if (d.getX() > maxx)
maxx = d.getX();
if (d.getY() < miny)
miny = d.getY();
if (d.getY() > maxy)
maxy = d.getY();
}
// Compute ranges
xrange = (maxx - minx) * BORDERFACTOR;
yrange = (maxy - miny) * BORDERFACTOR;
}
/**
* Called when the window needs painting. Computes X and Y range, scales.
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension s = getSize();
if (data.size() < 2) {
g.drawString("Insufficient data: " + data.size(), 10, 40);
return;
}
// Compute scale factors
double xfact = s.width / xrange;
double yfact = s.height / yrange;
// Scale and plot the data
for (int i = 0; i < data.size(); i++) {
Point2D d = (Point2D) data.get(i);
double x = (d.getX() - minx) * xfact;
double y = (d.getY() - miny) * yfact;
// Draw a 5-pixel rectangle centered, so -2 both x and y.
// AWT numbers Y from 0 down, so invert:
g.drawRect(((int) x) - 2, s.height - 2 - (int) y, 5, 5);
}
}
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
public static void main(String[] args) throws IOException {
final JFrame f = new JFrame("Grapher");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Grapher grapher = new Grapher();
f.setContentPane(grapher);
f.setLocation(100, 100);
f.pack();
ArrayList data = new ArrayList();
data.add("a");
grapher.setListData(data);
f.setVisible(true);
}
}
MVC Loop
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002. All rights
* reserved. Software written by Ian F. Darwin and others. $Id: LICENSE,v 1.8
* 2004/02/09 03:33:38 ian Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee cup"
* logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
* pioneering role in inventing and promulgating (and standardizing) the Java
* language and environment is gratefully acknowledged.
*
* The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
* inventing predecessor languages C and C++ is also gratefully acknowledged.
*/
// Investigate if you can get into a loop with a Swing-based MVC app;
// in particular, if you do setSelectedIndex on a choice, does it
// generate a secondary event? Push the button and see!
// If it does, you must be careful to avoid event propagation loops.
// This example doesn"t show it, but you can loop with other implementations.
// For example, if a changed() method updates the model"s data.
import java.awt.Button;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
public class MVCLoop {
public static void main(String[] a) {
Button b;
final JComboBox ch;
JFrame f = new JFrame("Testing");
Container cp = f.getContentPane();
cp.setLayout(new FlowLayout());
b = new Button("Set");
ch = new JComboBox();
cp.add(b);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int cur = ch.getSelectedIndex();
int len = ch.getItemCount();
cur++;
cur %= len;
ch.setSelectedIndex(cur);
}
});
ch.addItem("En/ett");
ch.addItem("Zwei");
ch.addItem("Tres");
ch.addItem("Four");
ch.addItem("Funf");
ch.addItem("Seis");
ch.addItem("Siete");
ch.addItem("Octo");
cp.add(ch);
ch.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(e);
}
});
f.pack();
f.setVisible(true);
}
}
MVC Pattern in Java 2
//[C] 2002 Sun Microsystems, Inc.---
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class RunMVCPattern {
public static void main(String [] arguments){
System.out.println("Example for the MVC pattern");
System.out.println();
System.out.println("In this example, a Contact is divided into");
System.out.println(" Model, View and Controller components.");
System.out.println();
System.out.println("To illustrate the flexibility of MVC, the same");
System.out.println(" Model will be used to provide information");
System.out.println(" to two View components.");
System.out.println();
System.out.println("One view, ContactEditView, will provide a Contact");
System.out.println(" editor window and will be paired with a controller");
System.out.println(" called ContactEditController.");
System.out.println();
System.out.println("The other view, ContactDisplayView, will provide a");
System.out.println(" display window which will reflect the changes made");
System.out.println(" in the editor window. This view does not support");
System.out.println(" user interaction, and so does not provide a controller.");
System.out.println();
System.out.println("Creating ContactModel");
ContactModel model = new ContactModel();
System.out.println("Creating ContactEditView and ContactEditController");
ContactEditView editorView = new ContactEditView(model);
model.addContactView(editorView);
createGui(editorView, "Contact Edit Window");
System.out.println("Creating ContactDisplayView");
ContactDisplayView displayView = new ContactDisplayView();
model.addContactView(displayView);
createGui(displayView, "Contact Display Window");
}
private static void createGui(JPanel contents, String title){
JFrame applicationFrame = new JFrame(title);
applicationFrame.getContentPane().add(contents);
applicationFrame.addWindowListener(new WindowCloseManager());
applicationFrame.pack();
applicationFrame.setVisible(true);
}
private static class WindowCloseManager extends WindowAdapter{
public void windowClosing(WindowEvent evt){
System.exit(0);
}
}
}
//Model
class Contact{
private String firstName;
private String lastName;
private String title;
private String organization;
private ContactView view;
public Contact(ContactView v){
firstName = "";
lastName = "";
title = "";
organization = "";
view = v;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String getTitle(){
return title;
}
public String getOrganization(){
return organization;
}
public void setFirstName(String newFirstName){
firstName = newFirstName;
}
public void setLastName(String newLastName){
lastName = newLastName;
}
public void setTitle(String newTitle){
title = newTitle;
}
public void setOrganization(String newOrganization){
organization = newOrganization;
}
public void updateModel(String newFirstName,
String newLastName, String newTitle,
String newOrganization){
if ((newFirstName != null) && !newFirstName.equals("")){
setFirstName(newFirstName);
}
if ((newLastName != null) && !newLastName.equals("")){
setLastName(newLastName);
}
if ((newTitle != null) && !newTitle.equals("")){
setTitle(newTitle);
}
if ((newOrganization != null) && !newOrganization.equals("")){
setOrganization(newOrganization);
}
updateView();
}
private void updateView(){
view.refreshContactView(firstName, lastName, title, organization);
}
}
interface ContactView{
public void refreshContactView(String firstName,
String lastName, String title, String organization);
}
class ContactModel{
private String firstName;
private String lastName;
private String title;
private String organization;
private ArrayList contactViews = new ArrayList();
public ContactModel(){
this(null);
}
public ContactModel(ContactView view){
firstName = "";
lastName = "";
title = "";
organization = "";
if (view != null){
contactViews.add(view);
}
}
public void addContactView(ContactView view){
if (!contactViews.contains(view)){
contactViews.add(view);
}
}
public void removeContactView(ContactView view){
contactViews.remove(view);
}
public String getFirstName(){ return firstName; }
public String getLastName(){ return lastName; }
public String getTitle(){ return title; }
public String getOrganization(){ return organization; }
public void setFirstName(String newFirstName){ firstName = newFirstName; }
public void setLastName(String newLastName){ lastName = newLastName; }
public void setTitle(String newTitle){ title = newTitle; }
public void setOrganization(String newOrganization){ organization = newOrganization; }
public void updateModel(String newFirstName, String newLastName,
String newTitle, String newOrganization){
if (!isEmptyString(newFirstName)){
setFirstName(newFirstName);
}
if (!isEmptyString(newLastName)){
setLastName(newLastName);
}
if (!isEmptyString(newTitle)){
setTitle(newTitle);
}
if (!isEmptyString(newOrganization)){
setOrganization(newOrganization);
}
updateView();
}
private boolean isEmptyString(String input){
return ((input == null) || input.equals(""));
}
private void updateView(){
Iterator notifyViews = contactViews.iterator();
while (notifyViews.hasNext()){
((ContactView)notifyViews.next()).refreshContactView(firstName, lastName, title, organization);
}
}
}
class ContactEditView extends JPanel implements ContactView{
private static final String UPDATE_BUTTON = "Update";
private static final String EXIT_BUTTON = "Exit";
private static final String CONTACT_FIRST_NAME = "First Name ";
private static final String CONTACT_LAST_NAME = "Last Name ";
private static final String CONTACT_TITLE = "Title ";
private static final String CONTACT_ORG = "Organization ";
private static final int FNAME_COL_WIDTH = 25;
private static final int LNAME_COL_WIDTH = 40;
private static final int TITLE_COL_WIDTH = 25;
private static final int ORG_COL_WIDTH = 40;
private ContactEditController controller;
private JLabel firstNameLabel, lastNameLabel, titleLabel, organizationLabel;
private JTextField firstName, lastName, title, organization;
private JButton update, exit;
public ContactEditView(ContactModel model){
controller = new ContactEditController(model, this);
createGui();
}
public ContactEditView(ContactModel model, ContactEditController newController){
controller = newController;
createGui();
}
public void createGui(){
update = new JButton(UPDATE_BUTTON);
exit = new JButton(EXIT_BUTTON);
firstNameLabel = new JLabel(CONTACT_FIRST_NAME);
lastNameLabel = new JLabel(CONTACT_LAST_NAME);
titleLabel = new JLabel(CONTACT_TITLE);
organizationLabel = new JLabel(CONTACT_ORG);
firstName = new JTextField(FNAME_COL_WIDTH);
lastName = new JTextField(LNAME_COL_WIDTH);
title = new JTextField(TITLE_COL_WIDTH);
organization = new JTextField(ORG_COL_WIDTH);
JPanel editPanel = new JPanel();
editPanel.setLayout(new BoxLayout(editPanel, BoxLayout.X_AXIS));
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new GridLayout(0, 1));
labelPanel.add(firstNameLabel);
labelPanel.add(lastNameLabel);
labelPanel.add(titleLabel);
labelPanel.add(organizationLabel);
editPanel.add(labelPanel);
JPanel fieldPanel = new JPanel();
fieldPanel.setLayout(new GridLayout(0, 1));
fieldPanel.add(firstName);
fieldPanel.add(lastName);
fieldPanel.add(title);
fieldPanel.add(organization);
editPanel.add(fieldPanel);
JPanel controlPanel = new JPanel();
controlPanel.add(update);
controlPanel.add(exit);
update.addActionListener(controller);
exit.addActionListener(new ExitHandler());
setLayout(new BorderLayout());
add(editPanel, BorderLayout.CENTER);
add(controlPanel, BorderLayout.SOUTH);
}
public Object getUpdateRef(){ return update; }
public String getFirstName(){ return firstName.getText(); }
public String getLastName(){ return lastName.getText(); }
public String getTitle(){ return title.getText(); }
public String getOrganization(){ return organization.getText(); }
public void refreshContactView(String newFirstName,
String newLastName, String newTitle,
String newOrganization){
firstName.setText(newFirstName);
lastName.setText(newLastName);
title.setText(newTitle);
organization.setText(newOrganization);
}
private class ExitHandler implements ActionListener{
public void actionPerformed(ActionEvent event){
System.exit(0);
}
}
}
class ContactEditController implements ActionListener{
private ContactModel model;
private ContactEditView view;
public ContactEditController(ContactModel m, ContactEditView v){
model = m;
view = v;
}
public void actionPerformed(ActionEvent evt){
Object source = evt.getSource();
if (source == view.getUpdateRef()){
updateModel();
}
}
private void updateModel(){
String firstName = null;
String lastName = null;
if (isAlphabetic(view.getFirstName())){
firstName = view.getFirstName();
}
if (isAlphabetic(view.getLastName())){
lastName = view.getLastName();
}
model.updateModel( firstName, lastName,
view.getTitle(), view.getOrganization());
}
private boolean isAlphabetic(String input){
char [] testChars = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"};
for (int i = 0; i < testChars.length; i++){
if (input.indexOf(testChars[i]) != -1){
return false;
}
}
return true;
}
}
class ContactDisplayView extends JPanel implements ContactView{
private JTextArea display;
public ContactDisplayView(){
createGui();
}
public void createGui(){
setLayout(new BorderLayout());
display = new JTextArea(10, 40);
display.setEditable(false);
JScrollPane scrollDisplay = new JScrollPane(display);
this.add(scrollDisplay, BorderLayout.CENTER);
}
public void refreshContactView(String newFirstName,
String newLastName, String newTitle, String newOrganization){
display.setText("UPDATED CONTACT:\nNEW VALUES:\n" +
"\tName: " + newFirstName + " " + newLastName +
"\n" + "\tTitle: " + newTitle + "\n" +
"\tOrganization: " + newOrganization);
}
}