34. Changing the Simulation Framework

Part of CS:2820 Object Oriented Software Development Notes, Fall 2015
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

 

Introduction

We have created a road-network simulation and a neuron-network simulation using one framework. The interesting question is, can we change the framework without destroying the other work we have done? The answer to this question is, to a large extent, yes. Adopting a simulation framework at the start of a project is important, but withing reasonably wide bounds, a change of framework is not outrageously expensive.

A New Framework

The framework we used before allowed us to schedule the deferred execution of λ expressions. Here is an alternative framework:

// Simulator.java

import java.util.PriorityQueue;

/** Framework for discrete event simulation
 *  @author Douglas Jones
 *  @version 4/18/2016
 */
class Simulator {

	/** Users create subclasses of event to schedule anything
	 */
        public static abstract class Event {
                public float time;       // the time of this event
                abstract void trigger(); // what to do at that time
        }

        private static PriorityQueue  eventSet
        = new PriorityQueue  (
                (Event e1, Event e2) -> Float.compare( e1.time, e2.time )
        );

	/** Call schedule to make act happen at time.
	 */
        public static void schedule( Event e ) {
                eventSet.add( e );
        }

	/** Call run() after scheduling some initial events
	 *  to run the simulation.
	 */
        public static void run() {
                while (!eventSet.isEmpty()) {
                        Event e = eventSet.remove();
                        e.trigger();
                }
        }
}

Scheduling An Event in the New Framework

To schedule an event in this new framework, we must create a new implementation of class Simulator.event that does what interests us and then schedule it. Where do we do this? Wherever there was a call to Simulator.schedule in the previous version of the code.

Looking at class Road using the previous framework, we find only one call to Simulator.schedule. Here it is, in context:

	void entryEvent( float t ) {
		// A vehicle arrives at the road entrance at time t
		Simulator.schedule(
			t+travelTime,
			(float time)->Road.this.exitEvent( time )
		);
	}

The most direct (but somewhat verbose) way to use our new framework here involves explicit declaration of a subclass of Simulator.event:

	void entryEvent( float t ) {
		// A vehicle arrives at the road entrance at time t

		class EntryEv extends Simulation.Event {
			void trigger() {
				Road.this.exitEvent( time );
			}
		}

		EntryEv e = new EntryEv();
		e.time = t + travelTime;
		Simulator.schedule( e );
	}

This code is verbose, and it is always annoying to be forced to invent a name that is used only once. The name we invented, entryEv is not very nice. The problem is, the name EntryEvent is already taken. Fortunately, this name is purely local, so awkward names are not too great a problem.

Had we started out with this scheduling framework, we'd have avoided using the suffix Event on anything that wasn't a subclass of Simulation.Event. We didn't make this decision, though, so we're stuck unless we want to undertake a global renaming.

Scheduling An Event in the New Framework

Java allows us to create anonymous subclasses. This allows us to eliminate the need for the name EntryEv used above and it allows for a more compact notation, although not as compact as we could accomplish with λ expressions:

	void entryEvent( float t ) {
		// A vehicle arrives at the road entrance at time t

		Simulation.Event e = new Simulation.Event() {
			void trigger() {
				Road.this.exitEvent( time );
			}
		};
		e.time = t + travelTime;
		Simulator.schedule( e );
	}

Here, what we've done is move the body of the subclass of Simulation.Event right into the new operation. Java doesn't allow arbitrary content in the new subclass if you do things this way. Specifically, it restricts the kinds of initializaiton permitted. Use the default initializer of the parent class without any inline initialization code, and Java can handle it.