Figure 8-16. Implementation of the boundary class SimulationForm.
Figure 8-16. Implementation of the boundary class SimulationForm.
In the section on control classes, it is mentioned that a class, referred to as SimulationControiler, will play the role of a control class used to control the behavior of the use case StartSimulation. Therefore, the SimulationController control class will serve as a coordinator between the boundary class and the system. SimulationController will receive the input data from the boundary class and use them accordingly in the simulation process.
The lifecycle of a control object is determined by the boundary class that is related to it. Usually, the boundary object creates an instance of the control class at the beginning of the execution of the use case and the control object "dies" when the use case is terminated.
How does a boundary object pass the input data to a control object? There are several ways to achieve this task. The best solution is to store the input parameters in a file of type Properties that will be used by method simulate(properties) of class SimulationController as shown in Figure 8-17.
As shown in this figure, class SimulationForm has an association with class SimulationController referred to as uses of stereotype communicate. The diagram says that a SimulationForm uses a SimulationController to perform a simulation. The association uses is unidirectional, meaning that class SimulationForm can access data and behavior from class SimulationController but not vice versa.
SimulationController is provided with a constructor which is the Java mechanism for creating new instances of a class. As the SimulationController is modeled following the Singleton pattern, the method getlnstance returns the unique instance of this class. The definition of class SimulationController includes two methods referred to as simulate but with different signatures; one does not use any parameters and the other uses a parameter named properties.
When method simulateQ is used, the controller object does not receive any input from the boundary object. In this case, the entity objects used in the simulation should provide all the initial data needed for the simulation process; they will have default values for parameters plantingDate, soilDepth, and wiltingPointPercent. This case is limiting, as it will perform simulations with fixed soil and plant data. The users cannot create scenarios to study the impact of different parameters on crop growth.
When method simulate(properties) is used, the boundary object can pass parameters to the control object to be used for populating different entity objects. Parameters are stored in a property file referred to as properties. Performing a simulation using initial data is the most common case in the simulation models, as it allows for studying the impact of one or more parameters on crop yield.
Other techniques can be used to pass parameters from a boundary class to the control class. One of them could be to provide the control class with simulate(list of parameters) methods that use a different number of parameters. For example, if the parameters passed to the control class are plantingDate and soilDepth, the control class should have the simulate(plantingDate, soilDepth) method defined in its class definition. In the case where the parameters passed to the control class are plantingDate, soilDepth, and wiltingPointPercent then the control class should have the simulate(plantingDate, soilDepth, wiltingPointPercent) method defined in its class definition. According to this solution, each time a parameter is added or its type is changed, the corresponding simulate method with the appropriate signature (parameters with corresponding types and in the right order) should be added to the class definition of the control class. Any changes in the class definition of the control class implies that the boundary class should be modified accordingly, as the boundary class will pass the simulation parameters to the control class. This solution strongly couples the boundary class to the control class, and as result, the system becomes inflexible. Changes occurring in one class have ramifications in other classes.
Using a container where all the parameters passing to the control class will be stored is a better solution. Such a container in the Java programming environment can be a Properties file. Using property files is a simple way in Java to implement a general communication between boundary and control classes. The control class needs only to know that a property file is used to store parameters; the number of parameters passes and their type is irrelevant. This type of communication increases the independence between boundary and control classes. Similarly, an XML file can be used to store the parameters that are passed to the control class.
The control class plays a key role in the simulation process, as it coordinates the messages objects send to each other. Therefore, it is a good programming practice to use the Singleton pattern when designing this class. As explained in Chapter 7, Design Patterns, the Singleton pattern allows for creating only one instance of the class. Method getlnstance will provide the unique instance of the control class.
In the section on entity classes, it is mentioned that entity classes are used to model concepts of the problem domain. A good start for depicting entity classes is the conceptual diagram for the Kraalingen approach previously developed. According to this diagram, the elements needed for the simulation model are classes Soil, Plant, and Weather. The control class SimulationController needs to have access to these objects in order to manage the flow of messages they need to send to each other. Figure 8-18 shows the relationship between controller and entity classes for the Kraalingen approach.
According to Figure 8-18, the relationship between the control and entity classes is modeled as a composition; the controller is conceived as a container that includes entity classes and shields them from the outside view. Thus, the controller manages the lifecycle of the entity objects. Because our problem has only one use case, entity objects are created at the beginning of the use case execution and they "die" when the use case is terminated.
The associations between the control and the entity classes are one-to-one associations. This means that the control class will only create one instance of each of the entity classes. Another important detail presented in Figure 8-18 is the fact that the associations between control and entity classes are unidirectional (i.e., the control object can access data and behavior from entity objects, but the entity objects do not have access to the control object).
Figure 8-19 shows the class diagram for the Kraalingen simulation approach. The diagram says that the SimulationForm communicates the input data to the SimulationController. The SimulationController uses the input data to populate instances of entity classes such as Plant, Soil, and Weather. Plant grows in Soil and both Plant and Soil use weather data to calculate their respective processes. When the simulation is terminated, the SimulationController will return to the SimulationForm the result of the simulation to be displayed to the user.
As shown in Figure 8-19, the SimulationForm communicates only with the SimulationController as previously mentioned in the Discover potential classes section. Thus, the control class incarnates the Façade pattern, presented in Chapter 7, Design Patterns. Entity objects are protected from the outsiders of the system. Having all the communication with boundary object pass through the control object makes the system independent of the outside environment. Changes that may occur in the behavior of entity objects will not affect the communication with boundary objects.
Was this article helpful?