See: LittleSimulator
Let's try to keep a history for would-be OO developers wishing to retrace the development in LittleSimulatorInJavaHistory.
// A developing implementation of LittleSimulator
public class Elevator
{
private int location;
public Elevator(){
location = 1;
}
public int whatFloor(){
return(location);
}
public void moveMe(){
if (location == 1)
location = 2;
else
location = 1;
}
}
public class Person
{
private int location;
public Person(){
location = 1;
}
public Person(int x){
location = x;
}
public int whatFloor(){
return(location);
}
public void getOnElevator(){
location = 0;
}
public void getOffElevator( int elevatorLocationX ){
location = elevatorLocationX;
}
}
public class Spike2
{
public static void main(String[] args){
Person person1 = new Person();
Person person2 = new Person(2);
Elevator elevator1 = new Elevator();
person1.getOnElevator();
elevator1.moveMe();
person2.getOnElevator();
person1.getOffElevator(elevator1.whatFloor());
elevator1.moveMe();
person2.getOffElevator(elevator1.whatFloor());
}
}
In AbbreviatedUmlAscii (omitting constructors):
Elevator
[location,whatFloor(),moveMe()]
Person
[location,whatFloor(),getOnElevator(),getOffElevator()]
Spike2 *Person@,Elevator@
[main()]
I was going to do a SuperAbstract description of LittleSimulator reconstructed from this code, preparatory to ModelTargeterSurface analysis. However I must be missing something: can a person choose where to get off an elevator (as opposed to asking the elevator to move to a floor)? So instead here's a SuperAbstract description of my uplifting (I'm a Brit) take on the problem domain; real-world descriptions in "quotes".
- building
- Has an immutable list of floors, sorted by their numbers ("one above the other"); another of elevators. Maintains the person lists for floors and elevators by setting itself as an observer of each member of the initial person list passed to the ground floor ("Tracks people moving from floor to floor, with everybody starting on the ground floor")
- person
- Has a waiting flag and a location reference which must be to either a floor or an elevator. ("Must be either on a floor or in an elevator.")
- waiting can only be set if location is a floor and is reset when it changes to an elevator ("Isn't necessarily waiting for an elevator, stops waiting on getting into one").
- location can be set from a floor to an elevator if the current floor reference of the elevator is to the current location ("Can get onto a lift - sorry, elevator - only while it's visiting the current floor..."); or from an elevator to the current floor reference of that elevator ("...and off at the floor the elevator is currently visiting.").
- Changes in location are notified to the building which updates the person lists for the elevator and floor involved.
- floor
- Has an immutable integer number (heuristically known never to be 13) and an immutable list of elevators that can visit it. A mutable list of persons can only contain persons whose location is set to the instance; this list is initially empty except for the ground floor which receives its initial list from the building.
- elevator
- Has a reference to its building and an immutable list of indexes into the building's list of floors, not necessarily a continuous sequence but guaranteed not to be resorted; and an iterable index to its position in that list. An initially empty mutable list of persons can only contain persons whose location is set to the instance.
Now left for revision by any interested reader as not really suitable for demonstrating
ModelTargeterSurface: too much domain design required as above, objects do not have a wide range of properties. But it could be an excellent problem domain for demonstrating several key aspects of practical OOP:
- The top-level decision about whether or not to model real-world entities (my analysis actually collapses two entities, in that the person observer is not really the building but a singleton god.)
- Collections, some mutable and some not
- The observer and singleton patterns
- Unit tests (and their applicability to interactive programs and simulations)
- Extensibility of both the design and implementation: what happens when you allow people to leave the building, add stairways; can you simulate emergency situations?
-
DavidWright
Looks good but how about identifying the methods for each object at a high level, as well as the attributes. For example whatFloor() is a method of Elevator at the top.
Give us a chance guv, I'm making this up as I go along. Also I always like to do the data design first.
Try writing the tests first. Then you only design the data you actually need to satisfy the tests.
[See CodeUnitTestFirst]
Let's do a bit of OverTheWallProgramming? - I'll design and you define the tests. Anyway it's going home time here in Blighty; over to you.
[See VirtualPairProgramming]
The tests given on LittleSimulator are ambiguous. What is our goal? Are we just modeling elevator behavior? If so, here are some tests:
- Person pushes button on floor 1
- Elevator moves to floor 1 and opens its doors.
- Person pushes button on floor 2
- Elevator moves to floor 2 and opens its doors.
- Person pushes floor 1 button inside elevator
- Elevator closes its doors, moves to floor 1 and opens its doors.
- Person pushes floor 2 button inside elevator
- Elevator closes its doors, moves to floor 2 and opens its doors.
- Person A pushes button on floor 1 then person B pushes button on floor 2
- Elevator moves to floor 1, opens its doors, waits n seconds, closes its door and moves to floor 2.
- Person A pushes button on floor 2 then person B pushes button on floor 1
- Elevator moves to floor 2, opens its doors, waits n seconds, closes its door and moves to floor 1.
I think I can satisfy these tests without modeling people, buildings or floors.
[If you want to do the example as ObjectOriented isn't it wise to model the basic entities?] I HaveThisPattern as can be seen from the above - DavidWright
Only if you need to. YouArentGonnaNeedIt. The system isn't going to control people, so modeling them is probably a waste of time. None of the tests interact with the building, so I can ignore that. The floors have buttons and the elevators move between them, but the tests probably just interact with the buttons (as a person would) and the floor is probably modeled as part of the elevator's state.
Shouldn't the LittleSimulator be more general, ie just be an engine that takes a file (or arrays if we don't want to make it too complex) representing objects, rules and events so it could be used to simulate a bank, gas (or petrol) station etc without re-coding each time?
It's only a SpikeSolution after all, and even as such quite tricky as this discussion demonstrates.
[If it's quite tricky, perhaps there's a simpler SpikeSolution lurking. The generalization suggested might actually be simpler. More general isn't always more complex, sometimes it's the other way around.]
Refactored from ModelTargeterSurface as it seems to belong here - DavidWright
Try this domain model.
- an Elevator holds Passengers with Destinations up to a Limit, and changes Floors at varying Speed.
- a Passenger has a Location (either a Floor or Elevator) and a Destination Floor
- a Bank is a number of Elevators servicing the same Floors and is aware of the direction of Destinations of Passengers at each
- the Traffic describes the arrival of new Passengers
Try these use cases.
- watch the activity of a Bank of Elevators from the perspective of a Passenger waiting at a given Floor.
- watch the activity of a given Elevator from the perspective of a Passenger on the Elevator.
- watch the activity of a given Passenger traveling on and off the Elevators (make choices for that passenger)
- run any combination of any number of these views simultainously.
Here is a main program.
main {
// create the model
bank = new Bank (10 floors, 3 elevators)
traffic = new HeavyUpTraffic (100 people, 5 minutes)
// launch three views
ElevatorSurface.openOn(bank.elevator(1))
FloorSurface.openOn(bank.floor(1))
PassengerSurface.openOn(traffic.passenger(25))
// begin the simulation
bank.carry(traffic)
}