CSC/ECE 517 Summer 2008/wiki2 6 a
Aim
This article aims at highlighting the new areas been explored in the fields of cohesion and coupling and how using agile methodologies help attain highly cohesive classes and to maintain loose coupling between those classes. Following these approaches we can get code which is more readable and maintainable. We encourage reader to visit the references provided at the end of the article to explore more on the research work done in this field.
Introduction
Cohesion and Coupling are concepts often discussed when referring to object-oriented programming. In fact, one of the primary goals of object-oriented programming is “to build highly cohesive classes and to maintain loose coupling between those classes” [1]. In the first section of this article, we provide the basic definition of cohesion, different types of cohesion, how it is measured, advantages and disadvantages of high cohesion and some examples showing implementation of this concept in real life scenarios. Next, we explain the concept of coupling, different types of cohesion, how it is measured, advantages and disadvantages of high coupling and some examples showing implementation of this concept in real life scenarios. In the third section of this article, we highlight we include a section on how using agile approaches maintain cohesion and coupling, and why this is important, it also discusses the importance of quality metrics, and how agile teams help support the same. In next section we discuss the vast research going on in this field and hence we have included a section on new work been done in this field. Lastly, we provide a conclusion to the topics discussed herein along with some recommended further reading and references.
Coupling
Coupling is a qualitative measure of the degree to which the classes, modules or subsystems are connected to one another. It can be defined as the amount of interaction of one object with another object, or one module with another module. For a good software design, it is always advisable to minimize coupling. Strong coupling means that one object or module is dependent on other object or module to perform an operation or task. It simply means that the object or module is strongly coupled with the implementation details of another object or module. With low coupling, a change in one module will not require a change in the implementation of another module. It is important to understand that low coupling does not mean no coupling, rather the goal is to minimize the coupling not eliminate it. A system with no coupling is, by definition, not a system. Low coupling indicates that each object or module performs independent tasks. In general, low coupling can be well explained by Law of demeter. It states that classes within a module or subsystem should have only limited knowledge of classes in other modules or subsystems. In simple terms, 'Law of Demeter' says "Each unit should only talk to its friends; don't talk to strangers".
Measuring Coupling
While it is impossible to avoid some level of coupling within systems, the goal is to reduce coupling as much as possible. Below are three metrics that can be used to determine the level of coupling within a system.
Coupling Between Objects (CBO)
CBO = sum(t) t = Total number of types that are referenced by a particular class, not including any possible super-classes, primitive types or common framework classes.
Lower CBO values indicate lower coupling.
Data Abstraction Coupling (DAC)
DAC = sum(a) a = Total number of types that are used for attribute declarations, not including primitive types, common framework classes, or types that are inherited from any possible super-classes.
Lower DC values indicate lower coupling.
Method Invocation Coupling (MIC)
MIC = nMIC / (N – 1) N = Total number of classes defined within the project. nMIC = Total number of classes that receive a message from the target class.
Lower MIC values indicate lower coupling.
Demeter's Law
Demeter's Law is a design principle that when applied to object-oriented programming means that object A can reference object B but object A cannot use object B to reference object C. Complying with this principle prevents object A from knowing that object B uses object C thereby reducing coupling. If object A needs to access a function of object C then it is up to object B to expose an operation encapsulating the reference to object C. The following example [2] illustrates how this could be done.
public float calculateTotal(Order order) { return order.getProducts().getTotalCost(); }
In the example object the object which implements calculateTotal()
is calling getTotalCost
on a Products
object which is exposed through order
. An alternative to this approach would be for the order object to expose this functionality as suggested by the following example.
public float calculateTotal(Order order) { return order.getTotalCost() } public class Order { // ... public float getTotalCost() { return products.getTotalCost(); } // ... }