Technical Manual

[ Return to Technical Manual Index ]


Design Analysis - Coupling and Cohesion

Contents

 

Introduction

The primary accomplishment of converting RHESSys from a procedural model to an object-oriented one, is that we have greatly improved the coupling of the model. Originally, RHESSys was about as tightly coupled as possible. There is a well-defined spatial hierarchy to the model. Briefly, it is as follows: a world contains multiple basins, a basin contains multiple hillslopes, a hillslope contains multiple zones, a zone contains multiple patches, and a patch contains multiple strata. There are various functions associated with each level of the hierarchy. For each function to operate it had to be passed a pointer to every higher level of the hierarchy. For example, for a zone function to operate, it had to be passed a pointer to a hillslope, basin, and zone. Thus, every level of the hierarchy exposed data to every other level. Essentially the hierarchy described above was purely conceptual. In fact, the hierarchy was entirely artificial, the reality was that there was essentially one data structure, a model, that took command line parameters.

In some sense, this was reasonable. RHESSys is really just one function. What it outputs depends on the command line arguments but in any given run of the simulation the computation is essentially the same. There are, however, certain drawbacks to this tight coupling. For example, changing the data stored at a given level might have repercussions throughout the model, since all data is exposed. Secondly, this design does not support linking to other modules. For example, currently all climatological data is stored in files and read in at the beginning of the simulation. This may be a good solution when the model is being run with dates when the climate information was known. However, for dates in the future, better solutions are available. For example, to run the simulation on future dates, you would first have to find someone with a climate model, ask her to run that model, store those results in a file, and finally run RHESSys. A much better solution would be to have the two models running concurrently and communicating their results to each other at each time step. Such communication was strictly impossible under the old implementation of RHESSys because climate data was read directly from the data object that stored the climate info. Now, however, the object that stores the climate data only exposes this information through accessor functions, so changing the way this data is gathered will involve only changing the implementation of one class, rather than changing the implementation of every function that needed to access the climate information. Indeed, removing this type of coupling is probably the biggest accomplishment of the Hydro Models team.

What follows is a break down of the Coupling and Cohesion of the model on a class by class basis. Only the major classes are included to save time and space.

Class by Class

The command line class stores all the information that is passed to the model through the command line. It is completely independent of all other classes in the model except for the tec class as detailed below. However, most other classes in the model need to know whether various

The tec class is now the model engine. Prior to our revision there was a tec struct that was simply a container for the tec file that is passed into RHESSys via the command line. Currently the tec class contains the tec file, but in addition it contains all the functions that read the tec file and manipulate the world. The tec class also contains the current date of the simulation. This data is only exposed to other elements of the model through parameter passing. The tec object uses a command line object and a world object to run. The tec object and the world object communicate strictly through accessor functions and parameter passing. The tec object and the command line object are more tightly coupled. Events are handled by allowing the tec object to directly manipulate the command line object and thus change the initial command line parameters that were passed to the model. This is accomplished by making the tec entry class, spawn of the tec class, a friend of the command line class. We chose this method over accessor functions for two reasons. First, only tec events can change the command line, so having a public member function that could change the command line variables seemed like a bad idea. Secondly, it was more efficient than functions, given that only one class could manipulate the command line.

The world class is loosely coupled with all other classes. It exposes it information to the tec class through accessor functions only. It communicates data to lower levels of the hierarchy through parameter passing. The world class, however, is not as cohesive as it could be. There is data stored at the world level that should be properly stored at the zone level. In our version of RHESSys, we have moved all the base stations to the zone level. Thus, base station information should be stored no higher than the zone level. However, in the old model base station information could be stored at all levels so the base stations were created at the world level, and info on the base stations was stored at the world level. We removed as much of this as possible, but we could not remove it all because our model has to take input in the same format as the previous versions. The format of the world file will have to be changed before we can remove this data form the world class.

These classes are all relatively independent entities. Each exposes data to higher levels of the hierarchy through accessor functions and to lower levels of the hierarchy through parameter passing. All data stored in each level is common to all lower levels, making these classes highly cohesive.

This is the class that stores climate information. Each object of this class is stored at the zone level. Only climate data is stored here, making it a very cohesive class. More importantly, this class only exposes data through accessor functions, so any other module in the simulation must request the data stored here. Thus, it is very easy to change the implementation of the climate data as mentioned above. Moving the information used to create the base stations out of the world class is the final step that it is needed to make the base stations, and therefore the climate completely independent from the rest of the model.

These classes are very tightly coupled. We discussed with the client ways to make the coupling a bit looser, but they involved greatly increasing the number of parameters that were passed to certain functions. Therefore, the client asked us to proceed with the implementation you'll find in the source code. The tight coupling of these classes is based on the fact that the real world structures that they represent are so tightly coupled. A patch represents a piece of ground, a canopy stratum is part of the plant life that lives on that ground, the snowpack is the snow that sits on the ground. It thus makes sense that these classes need to share a lot of data to perform their calculations. We have tried to make our implementation as clean as possible. We allow the canopy strata to query their respective patches through accessor functions and, similarly, we allow canopy strata to set some patch variables with mutator functions. This implementation is instead of one where patches pass 30 or more parameters to canopy stratum functions. It would not be impossible for a particular stratum to manipulate the data of an unrelated patch, but it could not be done by accident. That is, such a situation could only result from deliberately malicious programming.

Author: Hank Hoffmann

Introduction

Since we were able to write the GUI from scratch rather than from preexisting code, we were able to make the Java code as loosely coupled as possible while making each individual class fairly cohesive.

The main means of communication is via the passing of the CommandObj, which maintains all the information necessary to start the model, along with visualization options. Although all of the information within the CommandObj is not necessarily needed by all the classes that are passed this object, we pass the entire CommandObj as a matter of convenience. This type of coupling is known as Stamp Coupling.

What follows is a break down of the Coupling and Cohesion of the model on a class by class basis. Only the major classes are included to save time and space.

Class by Class

The CommandObj class maintains all of the possible command line options. Additionally, it contains all of the user specified visualization options. It is completely independent of all other classes. However, most other classes use the content of the CommandObj in one way or another.

The HydroGUI class is the main GUI class, and is a subclass of javax.swing.JPanel. It is composed of the user interface components of the GUI, the CommandObj, and the ModelTalker. It constructs the CommandObj, instantiates the ModelTalker with the CommandObj, and starts the ModelTalker thread. Therefore, the class is probably the least cohesive of all the Java classes. No methods are public.

The ModelTalker is a sub class of java.lang.Thread. It is composed of a StderrTalker, StdoutTalker, and a Process object. It's whole purpose is to start a new process, the C++ model, using the CommandObj passed to it by the HydroGUI. It also gets the error and output streams of the model, using them, along with the CommandObj, to instantiate both the StderrTalker, and the StdoutTalker. Thus, the class depends primarily upon the CommandObj passed to it by the HydroGUI. No methods are public except for the main run method, which is called via the call to ModelTalker.start() within HydroGUI.

This class is composed of the steam passed to it from the ModelTalker, and a JOutputWindow. It also is a subclass of java.lang.Thread. Within it's main run() method, the class reads from the stream, and fires this input to the JOutputWindow via an OutputEvent. No methods are public except for the main run method, which is called via the call to StderrTalker.start() within ModelTalker.

This class is composed of the steam passed to it from the ModelTalker, and a number JGraphicWindows, which is determined based on the visualization options carried by the CommandObj. It also is a subclass of java.lang.Thread. Within it's main run() method, the class reads from the stream, parses the input, determines which JGraphicWindow should be updated, and fires a GraphicOutputEvent to the appropriate JGraphicWindow. No methods are public except for the main run method, which is called via the call to StdoutTalk.start() within ModelTalker.

This is a simple subclass of java.awt.AWTEvent which carries one piece of data, a string. This data is accessed via setter and getter methods.

This is also a subclass of java.awt.AWTEvent. It carries more information, since it is used to render graphs of various variables used by the model. All of its data is accessed via setter and getter methods.

Simple window composed of the a few user interface components. The class implements the OutputEventListener interface in order to receive events fired to it. This along with the setVisible method is the only communication the class has with other classes.

Author: Skip Walker