|
The main goal (almost not evident) of design (from a low-level perspective) is to minimize coupling and
maximize cohesion. Coupling is the level of interdependency between a method and the environment,
(other methods, objects and classes), while cohesion is the level of uniformity of the method goal.
While coupling needs a low-level perspective, cohesion needs an higher point of view.
All patterns tends to reach these two objectives. Exactly knowing DP goals, we can more correctly apply the
Design Patterns, apply one of it without knowing nothing about it and, perhaps, try to invent another one.
Coupling
To low coupling tends to create more reusable methods. Obviously this is only a trend,
because it's not possible to write completely decoupled methods, or the program will not work!
Assuming the state of an object is the snapshot of its attributes in the time, all methods can belong to one of these three categories:
- Utility: doesn't use or modify object state for ex: Integer.toString(int), Math.cos(double)
- State View: use object state for ex: TextField.getText(), Object.toString()
- State Change: modify object state for ex: Vector.addElement(..), Hashtable.clear()
Every different type of method can treat input/output in one of these way:
- INPUT
- can take data from input parameter
- can take data from attributes and "static" methods
- can take data from attributes and methods
- OUTPUT
- can return a value, either an "handle" or a primitive one
- can alter objects whose handles are passed as parameters
- can alter static attibutes directly or through static methods
- can alter attibutes directly or through methods
- can throw an exception
An utility method can reach the lowest possible coupling:
- INPUT
- take only input parameters, and only if it needs them to make the output
- OUTPUT
- return a value (primitive or handle), or alter objects passed a parameters
- it produces all its output data (it doesn't call other methods)
A State/View method with lowest possible coupling does:
- INPUT
- takes input parameters and uses attributes or methods (class or instance ones) belonging to its class
(i.e. in every way but not from class members of others classes, constants excluded)
- OUTPUT
- return a value, alter parameters or throws an exception
A State/Change method with lowest possible coupling does:
- INPUT
- takes input parameters and uses attributes or methods (class or instance ones) belonging to its class
(i.e. in every way but not from class members of others classes, constants excluded)
- OUTPUT
- return a value, alter parameters or throws an exception , or through attributes and methods (class or instance ones)
belonging to its class (i.e. in every way but not with class members of others classes)
Cohesion
A method is cohesive when it does only a single, precise task, but not at low level of abstraction like in coupling. At low level methods
perform input, execute commands, do something. At an higher level they perform "tasks", like "clone" or "print", on other objects
or on local members: so a method "clone an object", "print a report", etc. The more the method is focused on a single goal
like clone(Object obj) or print(Report r), the more it will cohesive.
An high cohesion method will be simpler to understand, having to do only a single task, while a low cohesion method, performing so many tasks, will be difficult to
follow in application logic.
IAn high cohesion method will be simpler to reuse (how can you reuse a task-overloaded method?) and to extend, so it will
maximize reusability and extendibility.
If you cannot simply give a name to method, it's probably a low cohesion one, and this is true also if the name is too generic (a
method name should be composed by a verb, respecting your Coding standard).
When you pass a parameter to a method, and it does something different basing on values of the parameter itself, you are lowing the method cohesion.
But be aware of too much low cohesion, sometimes it's counterproductive:
handleKey(char c)
{
switch (c)
{
...
}
}
it's far better than handleAkey(), handleBKey(), handleCKey(), etc.
These are simple guidelines to obtain an high cohesion method:
the method must do only a single conceptual task. Es: makeReservation(), doPost(), getName().
If the operation it's not atomic, feel free to decompose it through other high cohesion methods
a method must not demand its behaviour to values of its parameters, obvoiusly trying to
balance the explosion of objects and the right cohesion of methods (this is a task where sometimes you have to use experience,
sometimes you have to use... common sense)
|