State Pattern in Java
//[C] 2002 Sun Microsystems, Inc.--- import java.awt.BorderLayout; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; public class RunStatePattern { public static void main(String[] arguments) { System.out.println("Example for the State pattern"); System.out.println(); if (!(new File("appointments.ser").exists())) { DataCreator.serialize("appointments.ser"); } System.out.println("Creating CalendarEditor"); CalendarEditor appointmentBook = new CalendarEditor(); System.out.println(""); System.out.println("Created. Appointments:"); System.out.println(appointmentBook.getAppointments()); System.out.println("Created. Creating GUI:"); StateGui application = new StateGui(appointmentBook); application.createGui(); System.out.println(""); } } interface State { public void save(); public void edit(); } interface Contact extends Serializable { public static final String SPACE = " "; public String getFirstName(); public String getLastName(); public String getTitle(); public String getOrganization(); public void setFirstName(String newFirstName); public void setLastName(String newLastName); public void setTitle(String newTitle); public void setOrganization(String newOrganization); } class ContactImpl implements Contact { private String firstName; private String lastName; private String title; private String organization; public ContactImpl() { } public ContactImpl(String newFirstName, String newLastName, String newTitle, String newOrganization) { firstName = newFirstName; lastName = newLastName; title = newTitle; organization = newOrganization; } 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 String toString() { return firstName + SPACE + lastName; } } interface Location extends Serializable { public String getLocation(); public void setLocation(String newLocation); } class LocationImpl implements Location { private String location; public LocationImpl() { } public LocationImpl(String newLocation) { location = newLocation; } public String getLocation() { return location; } public void setLocation(String newLocation) { location = newLocation; } public String toString() { return location; } } class FileLoader { public static Object loadData(File inputFile) { Object returnValue = null; try { if (inputFile.exists()) { if (inputFile.isFile()) { ObjectInputStream readIn = new ObjectInputStream( new FileInputStream(inputFile)); returnValue = readIn.readObject(); readIn.close(); } else { System.err.println(inputFile + " is a directory."); } } else { System.err.println("File " + inputFile + " does not exist."); } } catch (ClassNotFoundException exc) { exc.printStackTrace(); } catch (IOException exc) { exc.printStackTrace(); } return returnValue; } public static void storeData(File outputFile, Serializable data) { try { ObjectOutputStream writeOut = new ObjectOutputStream( new FileOutputStream(outputFile)); writeOut.writeObject(data); writeOut.close(); } catch (IOException exc) { exc.printStackTrace(); } } } class DataCreator { private static final String DEFAULT_FILE = "data.ser"; private static Calendar dateCreator = Calendar.getInstance(); public static void main(String[] args) { String fileName; if (args.length == 1) { fileName = args[0]; } else { fileName = DEFAULT_FILE; } serialize(fileName); } public static void serialize(String fileName) { try { serializeToFile(createData(), fileName); } catch (IOException exc) { exc.printStackTrace(); } } private static Serializable createData() { ArrayList appointments = new ArrayList(); ArrayList contacts = new ArrayList(); contacts.add(new ContactImpl("Test", "Subject", "Volunteer", "United Patterns Consortium")); Location location1 = new LocationImpl("Punxsutawney, PA"); appointments.add(new Appointment("Slowpokes anonymous", contacts, location1, createDate(2001, 1, 1, 12, 01), createDate(2001, 1, 1, 12, 02))); appointments.add(new Appointment("Java focus group", contacts, location1, createDate(2001, 1, 1, 12, 30), createDate(2001, 1, 1, 14, 30))); appointments .add(new Appointment("Something else", contacts, location1, createDate(2001, 1, 1, 12, 01), createDate(2001, 1, 1, 12, 02))); appointments.add(new Appointment("Yet another thingie", contacts, location1, createDate(2001, 1, 1, 12, 01), createDate(2001, 1, 1, 12, 02))); return appointments; } private static void serializeToFile(Serializable content, String fileName) throws IOException { ObjectOutputStream serOut = new ObjectOutputStream( new FileOutputStream(fileName)); serOut.writeObject(content); serOut.close(); } public static Date createDate(int year, int month, int day, int hour, int minute) { dateCreator.set(year, month, day, hour, minute); return dateCreator.getTime(); } } class Appointment implements Serializable { private String reason; private ArrayList contacts; private Location location; private Date startDate; private Date endDate; public Appointment(String reason, ArrayList contacts, Location location, Date startDate, Date endDate) { this.reason = reason; this.contacts = contacts; this.location = location; this.startDate = startDate; this.endDate = endDate; } public String getReason() { return reason; } public ArrayList getContacts() { return contacts; } public Location getLocation() { return location; } public Date getStartDate() { return startDate; } public Date getEndDate() { return endDate; } public void setReason(String reason) { this.reason = reason; } public void setContacts(ArrayList contacts) { this.contacts = contacts; } public void setLocation(Location location) { this.location = location; } public void setStartDate(Date startDate) { this.startDate = startDate; } public void setEndDate(Date endDate) { this.endDate = endDate; } public String toString() { return "Appointment:" + "\n Reason: " + reason + "\n Location: " + location + "\n Start: " + startDate + "\n End: " + endDate + "\n"; } } class CalendarEditor { private State currentState; private File appointmentFile; private ArrayList appointments = new ArrayList(); private static final String DEFAULT_APPOINTMENT_FILE = "appointments.ser"; public CalendarEditor() { this(DEFAULT_APPOINTMENT_FILE); } public CalendarEditor(String appointmentFileName) { appointmentFile = new File(appointmentFileName); try { appointments = (ArrayList) FileLoader.loadData(appointmentFile); } catch (ClassCastException exc) { System.err .println("Unable to load information. The file does not contain a list of appointments."); } currentState = new CleanState(); } public void save() { currentState.save(); } public void edit() { currentState.edit(); } private class DirtyState implements State { private State nextState; public DirtyState(State nextState) { this.nextState = nextState; } public void save() { FileLoader.storeData(appointmentFile, appointments); currentState = nextState; } public void edit() { } } private class CleanState implements State { private State nextState = new DirtyState(this); public void save() { } public void edit() { currentState = nextState; } } public ArrayList getAppointments() { return appointments; } public void addAppointment(Appointment appointment) { if (!appointments.contains(appointment)) { appointments.add(appointment); } } public void removeAppointment(Appointment appointment) { appointments.remove(appointment); } } class StateGui implements ActionListener { private JFrame mainFrame; private JPanel controlPanel, editPanel; private CalendarEditor editor; private JButton save, exit; public StateGui(CalendarEditor edit) { editor = edit; } public void createGui() { mainFrame = new JFrame("State Pattern Example"); Container content = mainFrame.getContentPane(); content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS)); editPanel = new JPanel(); editPanel.setLayout(new BorderLayout()); JTable appointmentTable = new JTable(new StateTableModel( (Appointment[]) editor.getAppointments().toArray( new Appointment[1]))); editPanel.add(new JScrollPane(appointmentTable)); content.add(editPanel); controlPanel = new JPanel(); save = new JButton("Save Appointments"); exit = new JButton("Exit"); controlPanel.add(save); controlPanel.add(exit); content.add(controlPanel); save.addActionListener(this); exit.addActionListener(this); mainFrame.addWindowListener(new WindowCloseManager()); mainFrame.pack(); mainFrame.setVisible(true); } public void actionPerformed(ActionEvent evt) { Object originator = evt.getSource(); if (originator == save) { saveAppointments(); } else if (originator == exit) { exitApplication(); } } private class WindowCloseManager extends WindowAdapter { public void windowClosing(WindowEvent evt) { exitApplication(); } } private void saveAppointments() { editor.save(); } private void exitApplication() { System.exit(0); } private class StateTableModel extends AbstractTableModel { private final String[] columnNames = { "Appointment", "Contacts", "Location", "Start Date", "End Date" }; private Appointment[] data; public StateTableModel(Appointment[] appointments) { data = appointments; } public String getColumnName(int column) { return columnNames[column]; } public int getRowCount() { return data.length; } public int getColumnCount() { return columnNames.length; } public Object getValueAt(int row, int column) { Object value = null; switch (column) { case 0: value = data[row].getReason(); break; case 1: value = data[row].getContacts(); break; case 2: value = data[row].getLocation(); break; case 3: value = data[row].getStartDate(); break; case 4: value = data[row].getEndDate(); break; } return value; } public boolean isCellEditable(int row, int column) { return ((column == 0) || (column == 2)) ? true : false; } public void setValueAt(Object value, int row, int column) { switch (column) { case 0: data[row].setReason((String) value); editor.edit(); break; case 1: break; case 2: data[row].setLocation(new LocationImpl((String) value)); editor.edit(); break; case 3: break; case 4: break; } } } }
1. | Dynamically changing the behavior of an object via composition (the State design pattern) | ||
2. | State pattern in Java 2 |