我不用打代码:)Exercise 42
//: c09:E42_GreenhouseLinkedList.java
//+M java E42_GreenhouseLinkedList
/****************** Exercise 42 *****************
 * In Chapter 8, locate the
 * GreenhouseControls.java example, which
 * consists of three files. In Controller.java,
 * the class EventSet is just a container. Change
 * the code to use a LinkedList instead of an
 * EventSet. This will require more than just
 * replacing EventSet with LinkedList; you'll
 * also need to use an Iterator to cycle through
 * the set of events.
 ***********************************************/
import java.util.*;abstract class Event {
  private long evtTime;
  public Event(long eventTime) {
    evtTime = eventTime;
  }
  public boolean ready() {
    return System.currentTimeMillis() >= evtTime;
  }
  abstract public void action();
  abstract public String description();
  public String toString() {
    return "Event: " + description();
  }
}class Controller {
  private LinkedList es = new LinkedList();
  public void addEvent(Event c) {
    System.out.println("Adding " + c);
    es.add(c);
  }
// This wouldn't work:
//  public void run() {
//    ListIterator it = es.listIterator();
//    while(es.size() != 0) {
//      while(it.hasNext()) {
//        Event e = (Event)it.next();
//        System.out.println("Testing " + e);
//        if(e.ready()) {
//          System.out.println("Running " + e);
//          e.action();
//          System.out.println(e.description());
//          int prevIndex = it.previousIndex();
//          // To prevent concurrent modification:
//          LinkedList tmp = new LinkedList(es);
//          tmp.remove(e);
//          es = tmp;
//          it = es.listIterator();
//        }
//      }
//    }
//  }
  public void run() {
    int index = 0;
    while(es.size() != 0) {
      Event e = (Event)es.get(index);
      if(e.ready()) {
        e.action();
        System.out.println(e.description());
        es.remove(index);
      }
      index = (index + 1) % es.size();
    }
  } 
}public class E42_GreenhouseLinkedList
    extends Controller {
  private boolean light = false;
  private boolean water = false;
  private String thermostat = "Day";
  private class LightOn extends Event {
    public LightOn(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here to
      // physically turn on the light.
      light = true;
    }
    public String description() {
      return "Light is on";
    }
  }
  private class LightOff extends Event {
    public LightOff(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here to
      // physically turn off the light.
      light = false;
    }
    public String description() {
      return "Light is off";
    }
  }
  private class WaterOn extends Event {
    public WaterOn(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here
      water = true;
    }
    public String description() {
      return "Greenhouse water is on";
    }
  }
  private class WaterOff extends Event {
    public WaterOff(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here
      water = false;
    }
    public String description() {
      return "Greenhouse water is off";
    }
  }
  private class ThermostatNight extends Event {
    public ThermostatNight(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here
      thermostat = "Night";
    }
    public String description() {
      return "Thermostat on night setting";
    }
  }
  private class ThermostatDay extends Event {
    public ThermostatDay(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here
      thermostat = "Day";
    }
    public String description() {
      return "Thermostat on day setting";
    }
  }
  // An example of an action() that inserts a
  // new one of itself into the event list:
  private int rings;
  private class Bell extends Event {
    public Bell(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Ring every 2 seconds, 'rings' times:
      System.out.println("Bing!");
      if(--rings > 0)
        addEvent(new Bell(
          System.currentTimeMillis() + 200));
    }
    public String description() {
      return "Ring bell";
    }
  }
  static int iterations = 3;
  private class Restart extends Event {
    public Restart(long eventTime) {
      super(eventTime);
    }
    public void action() {
      if(--iterations <= 0) System.exit(0);
      long tm = System.currentTimeMillis();
      // Instead of hard-wiring, you could parse
      // configuration information from a text
      // file here:
      rings = 5;
      addEvent(new ThermostatNight(tm));
      addEvent(new LightOn(tm + 100));
      addEvent(new LightOff(tm + 200));
      addEvent(new WaterOn(tm + 300));
      addEvent(new WaterOff(tm + 800));
      addEvent(new Bell(tm + 900));
      addEvent(new ThermostatDay(tm + 1000));
      // Can even add a Restart object!
      addEvent(new Restart(tm + 2000));
    }
    public String description() {
      return "Restarting system";
    }
  }
  public static void main(String[] args) {
    E42_GreenhouseLinkedList gc =
      new E42_GreenhouseLinkedList();
    long tm = System.currentTimeMillis();
    gc.addEvent(gc.new Restart(tm));
    gc.run();
  }
} ///:~
This one was a little tricky. Initially, it seems like a straightforward cut-and-paste, eliminating the handmade container class by replacing it with LinkedList. As you can see in the commented-out area, using an iterator became problematic, first because if you use the iterator to modify what you’re currently iterating through, you get a ConcurrentModificationException. This was “solved” by making a copy of the list before modifying, then removing the item and replacing the old list with the new one, then getting an iterator to the new list. However, this solution tended to start working, then hang.
There’s probably a way to get the iterator solution to work correctly, but I fell back to “the simplest thing that could possibly work” and realized that it would be simpler and more reliable just to manipulate the container directly rather than using an iterator.
In Restart.action( ) I’ve added a test to limit the number of repetitions so that the program completes in a short time.

解决方案 »

  1.   

    //42.  In Chapter 8, locate the GreenhouseControls.java example, which consists of three files. In Controller.java, the class EventSet is just a container. Change the code to use a LinkedList instead of an EventSet. This will require more than just replacing EventSet with LinkedList; you'll also need to use an Iterator to cycle through the set of events.
    import java.util.*;
    abstract class Event {
        private long evtTime;
        
        public Event(long eventTime) {
    evtTime = eventTime;
        }
        
        public boolean ready() {
    return System.currentTimeMillis() >= evtTime;
        }
      
        abstract public void action();
      
        abstract public String description();
    }
    class Controller {
        private LinkedList el = new LinkedList();
      
        public void addEvent(Event c) {
            el.add(c);
        }
      
        public void run() {
    /*
      How can I use an Iterator to do this?
      Iterator it = el.iterator();
      while(it.hasNext()) {
          Event e = (Event) it.next();
          if(e.ready()) {
       e.action();
       System.out.println(e.description());
    it.remove();
          }
              } 
    */
                       }
            }
        }
    }
    public class E42_GreenhouseControls extends Controller {
        private boolean light = false;
        
        private boolean water = false;
        
        private String thermostat = "Day";
        
        private class LightOn extends Event {
    public LightOn(long eventTime) {
           super(eventTime);
    }

    public void action() {
        light = true;
    }

    public String description() {
        return "Light is on";
    }
        }
        
        private class LightOff extends Event {
    public LightOff(long eventTime) {
        super(eventTime);
    }

    public void action() {
        light = false;
    }

    public String description() {
        return "Light is off";
    }
        }
        
        private class WaterOn extends Event {
    public WaterOn(long eventTime) {
        super(eventTime);
    }

    public void action() {
        water=true;
    }

    public String description() {
        return "Greenhouse water is on";
    }
        }
        
        private class WaterOff extends Event {
    public WaterOff(long eventTime) {
        super(eventTime);
    }

    public void action() {
        water=false;
    }

    public String description() {
        return "Greenhouse water is off";
    }
        }
      
        private class ThermostatNight extends Event {
    public ThermostatNight(long eventTime) {
        super(eventTime);
    }

    public void action() {
        thermostat="Night";
    }

    public String description() {
        return "Thermostat on night setting";
    }
        }
      
        private class ThermostatDay extends Event {
    public ThermostatDay(long eventTime) {
        super(eventTime);
    }

    public void action() {
        thermostat="Day";
    }

    public String description() {
        return "Thermostat on day setting";
    }
        }
      
        private int rings;
      
        private class Bell extends Event {
    public Bell(long eventTime) {
        super(eventTime);
    }

    public void action() {
        System.out.println("Bing!");
        if(--rings>0) {
    addEvent(new Bell(System.currentTimeMillis()+2000));
        }
    }

    public String description() {
        return "Ring bell";
    }
        }
      
        private class Restart extends Event {
    public Restart(long eventTime) {
        super(eventTime);
            }

    public void action() {
        long tm=System.currentTimeMillis();
        rings=5;
        addEvent(new ThermostatNight(tm));
        addEvent(new LightOn(tm+1000));
        addEvent(new LightOff(tm+2000));
        addEvent(new WaterOn(tm+3000));
        addEvent(new WaterOff(tm+8000));
        addEvent(new Bell(tm+9000));
        addEvent(new ThermostatDay(tm+10000));
        addEvent(new Restart(tm+20000));
    }

    public String description() {
        return "Restarting system";
    }
        }
        
        public static void main(String[] args) {
    E42_GreenhouseControls gc=new E42_GreenhouseControls();
    long tm=System.currentTimeMillis();
    gc.addEvent(gc.new Restart(tm));
    gc.run();
        }
    }