TP 6: Simulating the robotic factory model using MVC
Overview
In the previous practical session, you modified your robotic factory object model to implement the model interfaces of the graphical Canvas Viewer interface (canvas-viewer.jar) provided to you. This allowed visualizing your model as 2D figures with different colours, styles, and geometric shapes.
In this lab, you will define the behavioural view of your model to simulate it. Then, to visualize this simulation using the Canvas Viewer interface, you will need to create a class that implements the controller interface, enabling control over the display and simulation of your model.
In this lab, you will learn to:
- Define and run model behaviour with
behave() - Simulate robot movement and notify views (Observable)
- Implement the controller and launch the simulation
Specifying the model behaviour
You will now model the behavioural part of the robotic factory. This involves defining methods in the various classes of factory components to describe how their states, represented by the values of their attributes, evolve over time and in response to events in the factory.
- First, define a new method named
behave()in theComponentclass of your model. Initially, this method will be empty. Each factory component whose state can change over time will override this method to specify its behaviour when the factory operates. - In the
Factoryclass, override thebehave()method inherited from theComponentclass. For each component in the factory, call thebehave()method of its subcomponent. Thus, any method overridden by a subclass ofComponentwill be executed, simulating the specific behaviour of each subclass.
Moving robots
-
Specify the behaviour of the
Robotclass. Initially, this behaviour involves moving from one component to another within the factory. To do this, add an attribute to theRobotclass to hold a list of components the robot must visit as it moves through the factory. -
In the same
Robotclass, override thebehave()method inherited fromComponent.- Within this
behave()method, retrieve the first component from the list of components to be visited by the robot. Then, call a method namedmove()that you will define as described in the next section. - Before calling
move(), verify if the robot has reached the target component by checking if its position matches that of the component. - If so, retrieve the next component in the list and direct the robot towards it. When the end of the list is reached, the robot must return to the first component in the list of components to visit.
- Within this
-
In the
Robotclass, define themove()method.- In this method, increment (or decrement, as needed) the robot’s
xandycoordinates by a value defined by an attribute specifying the robot’sspeed, so that the robot moves closer to the component to visit. For now, assume there are no obstacles between the robot and the component it is heading toward.
- In this method, increment (or decrement, as needed) the robot’s
Observers
- Open the
canvas-viewer.jarlibrary located in thelibsdirectory of your Eclipse project for the robotic factory simulator. Within the packagefr.tp.inf112.projects.canvas.controller, you will find theCanvasViewerController,Observable, andObserverinterfaces. - Open the
CanvasViewerclass from thecanvas-viewer.jarlibrary. You will notice that this class, which serves as the view (and thus the observer) in the MVC pattern, implements theObserverinterface. This interface defines only one method,modelChanged(), which must be called by your model every time its data changes, so that the view(s) can refresh the data and keep the display consistent with the model's data. - Examine the body of the
modelChanged()method in theCanvasViewerclass. It simply calls the repaint methods of the menu bar and the panel that displays the shapes from your model. When displaying the menus in the menu bar, theStart AnimationandStop Animationmenus will be enabled or disabled depending on whether your model is currently running a simulation, as determined by a call to theisAnimationRunning()method from the controller interface presented later in this document.
Implementing the Observable interface
To notify the view when its data changes, the model must implement the Observable interface:
public class Factory extends Component implements Canvas, Observable { ... }
- This interface contains methods to add and remove observers. To implement them, declare an attribute in the
Factoryclass to hold its observers.
Notify the view(s) when the model’s data has changed
Since the simulator follows an MVC architecture, you will need to modify your model’s code so that any change in its data (such as the coordinates of a moving robot, for example) can notify the views that have been registered as observers of the model. This way, the views can refresh and display the updated data from the model.
- To achieve this, in the
Factoryclass, you will need to create anotifyObservers()method that will call themodelChanged()method of each observer that has been registered with the model. - This
notifyObservers()method should be called by the model whenever its data is modified, for all the classes in your model that need to be visualized by the graphical interface.
There are several ways to achieve this. A simple approach is to add an attribute of type Factory to the Component class, so that each component can call the notifyObservers() method of the Factory class whenever its data is changed through its setter methods.
Implementing the Controller interface
- Open the
CanvasViewerControllerinterface from thecanvas-viewer.jarlibrary. Create aSimulatorControllerclass implementing this interface. Pass an instance of this class to theCanvasViewerconstructor for visualizing your model. - The
CanvasViewerControllerinterface inherits from theObservableinterface. This means that the view registers with the model indirectly through the controller. Therefore, in your controller, you will need to maintain a reference to the model and implement the methods of theObservableinterface by calling the corresponding methods of the model.
By reading the Javadoc of the methods in the CanvasViewerController interface, provide implementations for the required methods. The controller is responsible for starting and stopping the simulation using the startAnimation() and stopAnimation() methods, which are called by the view when the corresponding menus are selected. Additionally, a call to the isAnimationRunning() method allows the view to check whether the simulation is currently running, so it can manage the activation of the animation control menus.
-
To implement the
startAnimation(),stopAnimation(), andisAnimationRunning()methods in your controller class, add an attribute to theFactoryclass to keep track of whether the simulation has started or not. -
Also, add the
startSimuation(),stopSimulation(), andisSimulationStarted()methods to theFactoryclass to manage this attribute. Do not forget to notify the observers when the value of this attribute changes. -
In the
startAnimation()method of the controller, copy the following code:factoryModel.startSimulation(); while (factoryModel.isSimulationStarted()) { factoryModel.behave(); try { Thread.sleep( 200 ); } catch (InterruptedException ex) { ex.printStackTrace(); } }
The graphical interface will take care of launching the simulation of your model in a dedicated task (thread or lightweight process) to avoid interrupting its display, which runs in a specific JVM task called the Event Dispatch Thread.
The sleep() method is used to wait for 200 milliseconds between each execution of the behave() method of the factory, to prevent the animation from running too quickly and allowing the user to better visualize the simulation. This value can be changed if needed.
Note the try-catch instructions used to handle the InterruptedException, which will be thrown if another task interrupts the task in which the simulator is running.
- Finally, implement the
stopAnimation()andisAnimationRunning()methods in your controller class by delegating these operations to the model.
Launching the simulation
To test your simulation, follow these steps:
- In a test class, instantiate a factory containing: 1 robot, 2 machines, and 1 charging station.
- Add these three components to the list of components to be visited by the robot.
- Instantiate the
CanvasViewerclass from the graphical interface, this time using the constructor that takes a controller as a parameter. - Verify that your robot moves correctly, visiting the two machines and the charging station sequentially.