Java/Design Pattern/State Pattern

Материал из Java эксперт
Перейти к: навигация, поиск

Dynamically changing the behavior of an object via composition (the State design pattern)

// : c07:Transmogrify.java
// Dynamically changing the behavior of an object via composition (the State design pattern).
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
abstract class Actor {
  public abstract void act();
}
class HappyActor extends Actor {
  public void act() {
    System.out.println("HappyActor");
  }
}
class SadActor extends Actor {
  public void act() {
    System.out.println("SadActor");
  }
}
class Stage {
  private Actor actor = new HappyActor();
  public void change() {
    actor = new SadActor();
  }
  public void performPlay() {
    actor.act();
  }
}
public class Transmogrify {
  public static void main(String[] args) {
    Stage stage = new Stage();
    stage.performPlay();
    stage.change();
    stage.performPlay();
  }
} ///:~





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;
      }
    }
  }
}





State pattern in Java 2

/*
The Design Patterns Java Companion
Copyright (C) 1998, by James W. Cooper
IBM Thomas J. Watson Research Center
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
public class StateDraw extends JFrame implements ActionListener {
  JToolBar tbar;
  Mediator med;
  public StateDraw() {
    super("State Drawing");
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    JPanel jp = new JPanel();
    getContentPane().add(jp);
    med = new Mediator();
    jp.setLayout(new BorderLayout());
    tbar = new JToolBar();
    tbar.setFloatable(false);
    jp.add("North", tbar);
    PickButton pick = new PickButton(this, med);
    tbar.add(pick);
    tbar.addSeparator();
    RectButton rect = new RectButton(this, med);
    tbar.add(rect);
    FillButton fill = new FillButton(this, med);
    tbar.add(fill);
    CircleButton circ = new CircleButton(this, med);
    tbar.add(circ);
    tbar.addSeparator();
    ClearButton clr = new ClearButton(this, med);
    tbar.add(clr);
    JCanvas canvas = new JCanvas(med);
    jp.add("Center", canvas);
    MouseApp map = new MouseApp(med);
    canvas.addMouseListener(map);
    MouseMoveApp mvap = new MouseMoveApp(med);
    canvas.addMouseMotionListener(mvap);
    setSize(new Dimension(400, 300));
    setVisible(true);
  }
  public void actionPerformed(ActionEvent e) {
    Command comd = (Command) e.getSource();
    comd.Execute();
  }
  static public void main(String[] argv) {
    new StateDraw();
  }
}

class MouseApp extends MouseAdapter {
  Mediator med;
  public MouseApp(Mediator md) {
    super();
    med = md;
  }
  public void mousePressed(MouseEvent e) {
    med.mouseDown(e.getX(), e.getY());
  }
  public void mouseReleased(MouseEvent e) {
    med.mouseUp(e.getX(), e.getY());
  }
}
class MouseMoveApp extends MouseMotionAdapter {
  Mediator med;
  public MouseMoveApp(Mediator md) {
    super();
    med = md;
  }
  public void mouseDragged(MouseEvent e) {
    med.mouseDrag(e.getX(), e.getY());
  }
}
class ArrowState extends State {
  private Mediator med;
  public ArrowState(Mediator md) {
    med = md;
  }
  public void mouseDown(int x, int y) {
    Vector drawings = med.getDrawings();
    for (int i = 0; i < drawings.size(); i++) {
      Drawing d = (Drawing) drawings.elementAt(i);
      if (d.contains(x, y))
        med.setSelected(d);
    }
  }
}
class CircleState extends State {
  private Mediator med; //save Mediator
  public CircleState(Mediator md) {
    med = md;
  }
  //Draw circle where mouse clicks
  public void mouseDown(int x, int y) {
    med.addDrawing(new visCircle(x, y));
  }
}
class ClearButton extends JButton implements Command {
  Mediator med;
  public ClearButton(ActionListener act, Mediator md) {
    super("C");
    setToolTipText("Clear");
    addActionListener(act);
    med = md;
  }
  public void Execute() {
    med.clear();
  }
}
class CircleButton extends JToggleButton implements Command {
  Mediator med;
  public CircleButton(ActionListener act, Mediator md) {
    super(" ");
    setSize(new Dimension(35, 35));
    setBorderPainted(true);
    setMargin(new Insets(5, 12, 5, 12));
    setToolTipText("Draw circle");
    addActionListener(act);
    med = md;
    med.registerCircleButton(this);
  }
  public Dimension getPreferredSize() {
    return new Dimension(35, 35);
  }
  public void paint(Graphics g) {
    super.paint(g);
    int h = getHeight();
    int w = getWidth();
    g.setColor(Color.black);
    g.drawArc(2, 2, h - 4, h - 4, 0, 360);
  }
  public void Execute() {
    med.startCircle();
  }
}
class State {
  public void mouseDown(int x, int y) {
  }
  public void mouseUp(int x, int y) {
  }
  public void mouseDrag(int x, int y) {
  }
  public void select(Drawing d, Color c) {
  }
}
interface Command {
  public void Execute();
}
class FillState extends State {
  private Mediator med; //save Mediator
  private Color color; //save current color
  public FillState(Mediator md) {
    med = md;
  }
  //Fill drawing if selected
  public void select(Drawing d, Color c) {
    color = c;
    if (d != null) {
      d.setFill(c); //fill that drawing
    }
  }
  //Fill drawing if you click inside one
  public void mouseDown(int x, int y) {
    Vector drawings = med.getDrawings();
    for (int i = 0; i < drawings.size(); i++) {
      Drawing d = (Drawing) drawings.elementAt(i);
      if (d.contains(x, y))
        d.setFill(color); //fill drawing
    }
  }
}
class JCanvas extends JPanel {
  Mediator med;
  public JCanvas(Mediator md) {
    med = md;
    med.registerCanvas(this);
    setBackground(Color.white);
  }
  public void paint(Graphics g) {
    super.paint(g);
    med.reDraw(g);
  }
}
class Mediator {
  boolean startRect;
  boolean dSelected;
  Vector drawings;
  Vector undoList;
  RectButton rectButton;
  FillButton fillButton;
  CircleButton circButton;
  PickButton arrowButton;
  JPanel canvas;
  Drawing selectedDrawing;
  StateManager stMgr;
  public Mediator() {
    startRect = false;
    dSelected = false;
    drawings = new Vector();
    undoList = new Vector();
    stMgr = new StateManager(this);
  }
  public void startRectangle() {
    stMgr.setRect();
    arrowButton.setSelected(false);
    circButton.setSelected(false);
    fillButton.setSelected(false);
  }
  public void startCircle() {
    stMgr.setCircle();
    rectButton.setSelected(false);
    arrowButton.setSelected(false);
    fillButton.setSelected(false);
  }
  public void startFill() {
    stMgr.setFill();
    rectButton.setSelected(false);
    circButton.setSelected(false);
    arrowButton.setSelected(false);
    stMgr.select(selectedDrawing, Color.red);
    repaint();
  }
  public void startArrow() {
    stMgr.setArrow();
    rectButton.setSelected(false);
    circButton.setSelected(false);
    fillButton.setSelected(false);
  }
  public Drawing getSelected() {
    return selectedDrawing;
  }
  public void fillSelected() {
    if (dSelected) {
      selectedDrawing.setFill(Color.red);
    }
  }
  public Vector getDrawings() {
    return drawings;
  }
  public void addDrawing(Drawing d) {
    drawings.addElement(d);
  }
  public void registerRectButton(RectButton rb) {
    rectButton = rb;
  }
  public void registerCircleButton(CircleButton cb) {
    circButton = cb;
  }
  public void registerArrowButton(PickButton ab) {
    arrowButton = ab;
  }
  public void registerFillButton(FillButton fb) {
    fillButton = fb;
  }
  public void registerCanvas(JPanel p) {
    canvas = p;
  }
  public void mouseDown(int x, int y) {
    stMgr.mouseDown(x, y);
    repaint();
  }
  public void mouseUp(int x, int y) {
    stMgr.mouseUp(x, y);
  }
  public void unpick() {
    dSelected = false;
    if (selectedDrawing != null) {
      selectedDrawing.setSelected(false);
      selectedDrawing = null;
      repaint();
    }
  }
  public void rememberPosition() {
    if (dSelected) {
      //Memento m = new Memento(d);
      //undoList.addElement(m);
    }
  }
  public void setSelected(Drawing d) {
    if (d != null) {
      dSelected = true;
      selectedDrawing = d;
      d.setSelected(true);
      repaint();
    }
  }
  public void pickRect(int x, int y) {
  }
  public void clear() {
    drawings = new Vector();
    undoList = new Vector();
    dSelected = false;
    selectedDrawing = null;
    repaint();
  }
  private void repaint() {
    canvas.repaint();
  }
  public void mouseDrag(int x, int y) {
    stMgr.mouseDrag(x, y);
  }
  public void reDraw(Graphics g) {
    g.setColor(Color.black);
    for (int i = 0; i < drawings.size(); i++) {
      Drawing v = (Drawing) drawings.elementAt(i);
      v.draw(g);
    }
  }
  public void undo() {
    if (undoList.size() > 0) {
      //get last element in undo list
      Object obj = undoList.lastElement();
      undoList.removeElement(obj); //and remove it
      //if this is an Integer, the last action was a new rectangle
      if (obj instanceof Integer) {
        //remove last created rectangle
        Object drawObj = drawings.lastElement();
        drawings.removeElement(drawObj);
      }
      //if this is a Memento, the last action was a move
      if (obj instanceof Memento) {
        //get the Memento
        Memento m = (Memento) obj;
        m.restore(); //and restore the old position
      }
      repaint();
    }
  }
}
class RectButton extends JToggleButton implements Command {
  Mediator med;
  public RectButton(ActionListener act, Mediator md) {
    super(" ");
    setSize(new Dimension(35, 35));
    setBorderPainted(true);
    setMargin(new Insets(5, 12, 5, 12));
    setToolTipText("Draw rectangle");
    addActionListener(act);
    med = md;
    med.registerRectButton(this);
  }
  public Dimension getPreferredSize() {
    return new Dimension(35, 35);
  }
  public void paint(Graphics g) {
    super.paint(g);
    int h = getHeight();
    int w = getWidth();
    g.setColor(Color.black);
    g.drawRect(4, 4, w - 8, h - 8);
  }
  public void Execute() {
    med.startRectangle();
  }
}
class UndoButton extends JButton implements Command {
  Mediator med;
  public UndoButton(ActionListener act, Mediator md) {
    super("U");
    //setSize(new Dimension(25,25));
    setMargin(new Insets(5, 12, 5, 12));
    setToolTipText("Undo");
    addActionListener(act);
    med = md;
  }
  public void Execute() {
    med.undo();
  }
}
class FillButton extends JToggleButton implements Command {
  Mediator med;
  public FillButton(ActionListener act, Mediator md) {
    super(" ");
    setSize(new Dimension(35, 35));
    setBorderPainted(true);
    setMargin(new Insets(5, 12, 5, 12));
    setToolTipText("Fill rectangle");
    addActionListener(act);
    med = md;
    med.registerFillButton(this);
  }
  public Dimension getPreferredSize() {
    return new Dimension(35, 35);
  }
  public void paint(Graphics g) {
    super.paint(g);
    int h = getHeight();
    int w = getWidth();
    g.setColor(Color.black);
    g.drawRect(4, 4, w - 8, h - 8);
    g.setColor(Color.red);
    g.fillRect(4, 10, w - 8, h - 14);
  }
  public void Execute() {
    if (isSelected()) {
      med.startFill();
    }
  }
}
class Memento {
  public Memento(Drawing d) {
  }
  public void restore() {
  }
}
class RectState extends State {
  private Mediator med; //save the Mediator here
  public RectState(Mediator md) {
    med = md;
  }
  //create a new Rectangle where mode clicks
  public void mouseDown(int x, int y) {
    med.addDrawing(new visRectangle(x, y));
  }
}
class StateManager {
  private State currentState;
  RectState rState;
  ArrowState aState;
  CircleState cState;
  FillState fState;
  public StateManager(Mediator med) {
    rState = new RectState(med);
    cState = new CircleState(med);
    aState = new ArrowState(med);
    fState = new FillState(med);
    currentState = aState;
  }
  public void setRect() {
    currentState = rState;
  }
  public void setCircle() {
    currentState = cState;
  }
  public void setFill() {
    currentState = fState;
  }
  public void setArrow() {
    currentState = aState;
  }
  public void mouseDown(int x, int y) {
    currentState.mouseDown(x, y);
  }
  public void mouseUp(int x, int y) {
    currentState.mouseUp(x, y);
  }
  public void mouseDrag(int x, int y) {
    currentState.mouseDrag(x, y);
  }
  public void select(Drawing d, Color c) {
    currentState.select(d, c);
  }
}
class Drawing {
  protected int x, y, w, h;
  protected Rectangle rect;
  protected boolean selected;
  protected boolean filled;
  protected Color fillColor;
  //-------------------------------------------
  public void setSelected(boolean b) {
    selected = b;
  }
  public void draw(Graphics g) {
  }
  public void move(int xpt, int ypt) {
    x = xpt;
    y = ypt;
  }
  public boolean contains(int x, int y) {
    return rect.contains(x, y);
  }
  protected void saveAsRect() {
    rect = new Rectangle(x - w / 2, y - h / 2, w, h);
  }
  protected void setFill(Color c) {
    filled = true;
    fillColor = c;
  }
}
class visCircle extends Drawing {
  public visCircle(int xpt, int ypt) {
    x = xpt;
    y = ypt;
    w = 40;
    h = 30;
    saveAsRect();
  }
  //-------------------------------------------
  public void draw(Graphics g) {
    g.drawArc(x, y, w, h, 0, 360);
    if (filled) {
      g.setColor(fillColor);
      g.fillArc(x, y, w, h, 0, 360);
    }
    if (selected) {
      g.setColor(Color.black);
      g.fillRect(x + w / 2, y - 2, 4, 4);
      g.fillRect(x - 2, y + h / 2, 4, 4);
      g.fillRect(x + w / 2, y + h - 2, 4, 4);
      g.fillRect(x + w - 2, y + h / 2, 4, 4);
    }
  }
}
//===============================================
class circleMemento extends Memento {
  visCircle circ;
  //saved fields- remember internal fields
  //of the specified visual rectangle
  int x, y, w, h;
  public circleMemento(visCircle r) {
    super(r);
    circ = r;
    x = circ.x;
    y = circ.y;
    w = circ.w;
    h = circ.h;
  }
  //-------------------------------------------
  public void restore() {
    //restore the internal state of
    //the specified rectangle
    circ.x = x;
    circ.y = y;
    circ.h = h;
    circ.w = w;
  }
}
class visRectangle extends Drawing {
  public visRectangle(int xpt, int ypt) {
    x = xpt;
    y = ypt;
    w = 40;
    h = 30;
    saveAsRect();
  }
  //-------------------------------------------
  public void draw(Graphics g) {
    g.drawRect(x, y, w, h);
    if (filled) {
      g.setColor(fillColor);
      g.fillRect(x, y, w, h);
    }
    if (selected) {
      g.setColor(Color.black);
      g.fillRect(x + w / 2, y - 2, 4, 4);
      g.fillRect(x - 2, y + h / 2, 4, 4);
      g.fillRect(x + w / 2, y + h - 2, 4, 4);
      g.fillRect(x + w - 2, y + h / 2, 4, 4);
    }
  }
}

class rectMemento extends Memento {
  visRectangle rect;
  //saved fields- remember internal fields
  //of the specified visual rectangle
  int x, y, w, h;
  public rectMemento(visRectangle r) {
    super(r);
    rect = r;
    x = rect.x;
    y = rect.y;
    w = rect.w;
    h = rect.h;
  }
  //-------------------------------------------
  public void restore() {
    //restore the internal state of
    //the specified rectangle
    rect.x = x;
    rect.y = y;
    rect.h = h;
    rect.w = w;
  }
}
class PickButton extends JToggleButton implements Command {
  Mediator med;
  public PickButton(ActionListener act, Mediator md) {
    super(new ImageIcon("arrow.gif"));
    setSize(new Dimension(35, 35));
    setBorderPainted(true);
    setMargin(new Insets(0, 0, 0, 0));
    setToolTipText("Select drawing element");
    addActionListener(act);
    med = md;
    med.registerArrowButton(this);
  }
  //-------------------------------------------
  public void Execute() {
    med.startArrow();
  }
}