Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
202
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

Example

Note:

For a full working example of this code example, with additional supporting classes and/or a RunPattern class, see “ State ” on page 414 of the “ Full Code Examples ” appendix.

Inner classes are most appropriate for States. They are very closely coupled with their enclosing class and have direct access to its attributes. The following example shows how this works in practice.

A standard feature of applications is that they only save files when necessary: when changes have been made. When changes have been made but a file has not been saved, its state is referred to as dirty. The content might be different from the persistent, saved version. When the file has been saved and no further changes have been made, the content is considered clean. For a clean state, the content and the file will be identical if no one else edits the file.

This example shows the State pattern being used to update Appointments for the PIM, saving them to a file as necessary.

The State transition diagram for a file is shown in Figure 2.13.

Figure 2.13. State transition diagram for a file

Two states (CleanState and DirtyState) implement the State interface. The states are responsible for determining the next state, which in this case is reasonably easy, as there are only two.

The State interface defines two methods, save and edit. These methods are called by the CalendarEditor when appropriate.

Example 2.38 State.java

1.public interface State{

2.public void save();

3.public void edit();

4.}

The CalendarEditor class manages a collection of Appointment objects.

Example 2.39 CalendarEditor.java

1.import java.io.File;

2.import java.util.ArrayList;

3.public class CalendarEditor{

4.private State currentState;

5.private File appointmentFile;

6.private ArrayList appointments = new ArrayList();

7.private static final String DEFAULT_APPOINTMENT_FILE = "appointments.ser";

9.public CalendarEditor(){

10.this(DEFAULT_APPOINTMENT_FILE);

11.}

12.public CalendarEditor(String appointmentFileName){

13.appointmentFile = new File(appointmentFileName);

77

14.try{

15. appointments = (ArrayList)FileLoader.loadData(appointmentFile);

16.}

17.catch (ClassCastException exc){

18. System.err.println("Unable to load information. The file does not contain a list of appointments.");

19.}

20.currentState = new CleanState();

21.}

22.

23.public void save(){

24.currentState.save();

25.}

26.

27.public void edit(){

28.currentState.edit();

29.}

30.

31.private class DirtyState implements State{

32.private State nextState;

33.

34.public DirtyState(State nextState){

35.

this.nextState = nextState;

36.

}

37.

 

38.public void save(){

39. FileLoader.storeData(appointmentFile, appointments);

40. currentState = nextState;

41.}

42.public void edit(){ }

43.}

44.

45.private class CleanState implements State{

46.private State nextState = new DirtyState(this);

48.public void save(){ }

49.public void edit(){ currentState = nextState; }

50.}

51.

52.public ArrayList getAppointments(){

53.return appointments;

54.}

55.

56.public void addAppointment(Appointment appointment){

57.if (!appointments.contains(appointment)){

58. appointments.add(appointment);

59.}

60.}

61.public void removeAppointment(Appointment appointment){

62.appointments.remove(appointment);

63.}

64.}

The class StateGui provides an editing interface for the CalendarEditor's appointments. Notice that the GUI has a reference to the CalendarEditor, and that it delegates edit or save actions to the editor. This allows the editor to perform the required actions and to update its state as appropriate.

Example 2.40 StateGui.java

1.import java.awt.Container;

2.import java.awt.BorderLayout;

3.import java.awt.event.ActionListener;

4.import java.awt.event.WindowAdapter;

5.import java.awt.event.ActionEvent;

6.import java.awt.event.WindowEvent;

7.import javax.swing.BoxLayout;

8.import javax.swing.JButton;

9.import javax.swing.JComponent;

10.import javax.swing.JFrame;

11.import javax.swing.JPanel;

12.import javax.swing.JScrollPane;

13.import javax.swing.JTable;

14.import javax.swing.table.AbstractTableModel;

15.import java.util.Date;

16.public class StateGui implements ActionListener{

17.private JFrame mainFrame;

18.private JPanel controlPanel, editPanel;

78

19.private CalendarEditor editor;

20.private JButton save, exit;

22.public StateGui(CalendarEditor edit){

23.editor = edit;

24.}

25.

26.public void createGui(){

27.mainFrame = new JFrame("State Pattern Example");

28.Container content = mainFrame.getContentPane();

29.content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));

31.editPanel = new JPanel();

32.editPanel.setLayout(new BorderLayout());

33.JTable appointmentTable = new JTable(new StateTableModel((Appointment [])

editor.getAppointments().toArray(new Appointment[1])));

34.editPanel.add(new JScrollPane(appointmentTable));

35.content.add(editPanel);

36.

37.controlPanel = new JPanel();

38.save = new JButton("Save Appointments");

39.exit = new JButton("Exit");

40.controlPanel.add(save);

41.controlPanel.add(exit);

42.content.add(controlPanel);

43.

44.save.addActionListener(this);

45.exit.addActionListener(this);

47.mainFrame.addWindowListener(new WindowCloseManager());

48.mainFrame.pack();

49.mainFrame.setVisible(true);

50.}

51.

52.

53.public void actionPerformed(ActionEvent evt){

54.Object originator = evt.getSource();

55.if (originator == save){

56. saveAppointments();

57.}

58.else if (originator == exit){

59. exitApplication();

60.}

61.}

63.private class WindowCloseManager extends WindowAdapter{

64.public void windowClosing(WindowEvent evt){

65. exitApplication();

66.}

67.}

69.private void saveAppointments(){

70.editor.save();

71.}

72.

73.private void exitApplication(){

74.System.exit(0);

75.}

76.

77.private class StateTableModel extends AbstractTableModel{

78.private final String [] columnNames = {

79. "Appointment", "Contacts", "Location", "Start Date", "End Date" };

80. private Appointment [] data;

81.

82.public StateTableModel(Appointment [] appointments){

83.

data = appointments;

84.

}

85.

 

86.public String getColumnName(int column){

87. return columnNames[column];

88.}

89.public int getRowCount(){ return data.length; }

90.public int getColumnCount(){ return columnNames.length; }

91.public Object getValueAt(int row, int column){

92. Object value = null;

93. switch(column){

94. case 0: value = data[row].getReason();

95. break;

79

96.

case 1: value = data[row].getContacts();

97.

break;

98.

case 2: value = data[row].getLocation();

99.

break;

100.

case 3: value = data[row].getStartDate();

101.

break;

102.

case 4: value = data[row].getEndDate();

103.

break;

104.}

105.return value;

106.}

107.public boolean isCellEditable(int row, int column){

108.return ((column == 0) || (column == 2)) ? true : false;

109.}

110.public void setValueAt(Object value, int row, int column){

111.switch(column){

112.

case 0: data[row].setReason((String)value);

113.

editor.edit();

114.

break;

115.

case 1:

116.

break;

117.

case 2: data[row].setLocation(new LocationImpl((String)value));

118.

editor.edit();

119.

break;

120.

case 3:

121.

break;

122.

case 4:

123.

break;

124.}

125.}

126.}

127.}

80