10.10 Using Cohesion and Coupling to Evaluate Designs

 < Day Day Up > 



10.10 Using Cohesion and Coupling to Evaluate Designs

A program is a very complex logic puzzle. If a program is regarded as a simple state machine, and every statement is allowed to access every data item, then the complexity of a program is all the possible values in memory that every variable can have multiplied by every statement in a program. So, if a program has N memory variables, each having M possible values, a line of code that can access any of those values would have N * M possible consequences. If we multiply this by the number of statements executed in a program (S), we get N * M * S possible results for a program, a number which while finite is probably not manageable by a person for a program of any significant size.

This is what makes it very easy to write programs that are impossible to understand. Languages that allow addressing of any piece of data, such as C/C++, immediately make the maximum level of complexity of the program obtainable and is one of the reasons the use of pointers was eliminated in Java. The same problem existed in older FORTRAN programs, where all the data values were kept in a single common block and could be accessed anywhere in a program. Structured programming was supposed to solve these problems but, unfortunately, structured programming by itself did not limit the scope of the data. A great description of a program given to me was that "the program is very well structured, but it is like the data was just poured into it."

To get around this program of unstructured data, the concept of encapsulation was introduced by Parnas [PAR72]. With encapsulation, if data is hidden inside of a function and only allowed to be acted on in well-defined ways by program statements in that function, the data and the function could be treated as a single entity in the program, thus reducing the amount of data each statement can act on and decreasing the overall program complexity. This idea of encapsulation is applied to OOP in that the data is now encapsulated in the object, and only methods for that object can act on that data. If the encapsulation is complete, then the object can be treated as a single entity in the program, not as a number of separate values and statements, thus reducing the overall complexity significantly.

How well the encapsulation has been achieved can be evaluated by looking at the cohesiveness and coupling of an object. Cohesion and coupling have already been introduced in the discussion of how to do exception handling in Chapter 6; here, the concepts are further developed and applied to methods and objects. Cohesion for a method is the property of doing a limited number of things, ideally just one thing. If a method must implement more than one behavior, other objects or methods should be created and used for those behaviors. Cohesion for an object requires that the object represent one entity, even though that one entity could be made up of numerous other entities, such as a car having an engine and tires. Still, the object is one thing, a car. Coupling is concerned with how much of the internal details of the object or method must be known by other methods or objects for the object to be implemented. For methods, coupling means that the data that will be used by the method has a well-defined path into that method. For procedural methods, this means that no data is sent to the method except via parameters. For methods that are part of objects, some of the data can be part of the object, but the data used is limited and access to it is controlled and well understood as part of the object state. For objects, coupling means that no other object has access to its state (variables and data) except through well-controlled access, such as methods.

The basic principles here are that, as an object or a method does more things, its cohesion goes down, and as the access to it becomes more intertwined with other objects its coupling goes up. The ideal is to raise cohesion while lowering coupling. Doing so will better isolate the data, and hopefully make the program less complex.

It was already shown that cohesion and coupling can be used to evaluate the error handling in the SortedPrintTable objects of Chapter 5. In these objects, when an error occurred it was printed to the terminal from within the object itself. Chapter 6 suggested that this was a bad idea, as this procedure locked the object to a specific execution environment and showed that exceptions were a better way to handle this situation. Cohesion and coupling can be used to explain this further. First, the objects tried to do two things: handle requests for the object and handle errors for the object. Second, they were too tightly coupled to the environment in which they were run; in this case, they relied on the fact that the program would be terminal based. The use of exceptions was an attempt to break this coupling of the object to the environment and to allow the object to be concerned with how to handle the table, not what to do with errors.

Cohesion and coupling do not find errors, but they are at the root of many errors, so they are good indicators of designs that are likely to be more error prone. For example, the classification implementation of the MoveController object in Exhibit 6 (Program10.5a) is more tightly coupled because the two classes that are present, the MoveController and the ConcurrentBall, both are represented by the same object. This might or might not cause a problem, but it suggests a higher probability of error in the classification design than the composition design. This, indeed, proved to be the case, as was shown with call to wait in the move method. Generally, designs that use composition have higher cohesion and lower coupling than designs that use classification. So, if no other factors are influencing the decision, as is generally true with utility classes, the decision about which approach to use should always favor composition.

This does not mean that classification should never be used, as it really depends on the problem that is being solved. For example, the Java AWT creates components by extending the Component class. In this case, the AWT components really are just types of components, and they must extend components to be used properly. An external factor also influences the design, as the Component class is not a utility class in the AWT, thus making classification the best choice for design of the AWT. Many AWT classes also extend Container, in which case whether or not classification is the best design is less clear. Problem 10.3 looks further at this issue.



 < Day Day Up > 



Creating Components. Object Oriented, Concurrent, and Distributed Computing in Java
The .NET Developers Guide to Directory Services Programming
ISBN: 849314992
EAN: 2147483647
Year: 2003
Pages: 162

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net