Name: Saad Aslam
Roll No: 0043-BSCS-16
Section: E2
Subject: Object Oriented Programming
Topics :
Ø Coupling
Ø Reduce Coupling
§ Calling Separate Methods
§ Encapsulation
§ Responsibilty driven design
§ Localizing Changes
Ø Implicit Coupling
Ø Cohesion
Ø Refactoring
§ Refactoring and testing
§ Refactoring for language independence
CH #6 Coupling and Cohesion
REDUCE
COUPLING
Ø By calling separate methods:
If same code
is used in different methods again and again than instead of writing the same code in different methods ,we can
implement a separate method and write that code which is similar in different
methods and then call that code in that methods where the code was used.
Ø Encapsulation:
To avoid
tight coupling ,we need to use encapsulation by making all public fields to
public .This will help us in decoupling the classes and hence decrease in tight
coupling.
(“Never make
fields public!”)
Proper
encapsulation in
classes reduces
coupling and thus
leads to a better
The encapsulation guideline (hiding
implementation information from view) suggests that only information about what
a class can do should be visible to the outside, not about how it
does it.This has a great advantage: if no other class knows how our information
is stored, then we can easily change how it is stored without breaking other
classes.
Ø
Responsibility-driven design:
Responsibility-driven
design expresses the idea that each class should be responsible for handling
its own
data. Often, when we need to add some new functionality to an application, we
need to
ask ourselves in which class we should add a method to implement this new
function.
Which
class should be responsible for the task? The answer is that the class that is
responsible
for storing some data should also be
responsible for manipulating it.
Ø
Localizing Changes:
Another
aspect of the decoupling and responsibility principles is that of localizing
change. We
aim
to create a class design that makes later changes easy by localizing the
effects of a change.
Ideally,
only a single class needs to be changed to make a modification. Sometimes
several
classes need
change, but we then aim at this being as few classes as possible. In addition,
the
changes
needed in other classes should be obvious, easy to detect, and easy to carry
out.
To a large
extent, we can achieve this by following good design rules such as using
responsibility-driven
design and aiming for loose coupling and high cohesion. In addition, however,
we should
have modification and extension in mind when we create our applications. It is
important
to
anticipate that an aspect of our program might change, in order to make this
change easy.
WORSE FORM OF COUPLING
Implicit Coupling:
There is an even worse form of
coupling: implicit coupling.
Implicit coupling is a situation
where one class depends on the internal information of another,but this
dependence is not immediately obvious. The tight coupling in the case of the
public fields was not good, but at least it was obvious. If we change the
public fields in one class and forget about the other, the application will not
compile any more and the compiler will point out the problem. In cases of
implicit coupling, omitting a necessary change can go undetected.
This is a fundamental problem,
because every time a command is added, the help text needs to be changed, and
it is very easy to forget to make this change. The program compiles and runs, and
everything seems fine. A maintenance programmer may well believe that the job
is finished and release a program that now contains a bug.
This is an
example of implicit coupling.
THINKING AHEAD
Q:What is
Model View Controller Pattern?
COHESION
A unit of
code should always be responsible for one, and only one, task. The principle of
cohesion can be applied to classes and methods: classes should display a high
degree of cohesion, and so should methods.
Ø
Cohesion in Methods:
When we
talk about cohesion of methods, we seek to express the ideal that any one
method should be responsible for one, and only one, well-defined task.We can
see an example of a cohesive method in the Game class. This class
has a private method named printWelcome
to show the opening text, and this method is
called when the game starts in the play method.
Ø
Cohesion
in Classes:
The rule
of cohesion of classes states that each class should represent one single,
well-defined entity in the problem domain.
BENEFITS OF COHESION
There are
several ways in which high cohesion benefits a design. The two most important
ones
are readability
and reuse
REFACTORING
Refactoring is the activity of restructuring
existing classes and methods to adapt them to
changed
functionality and requirements. Often in the lifetime of an application,
functionality is
gradually
added. One common effect is that, as a side-effect of this, methods and classes
slowly
grow in
length.
Refactoring is the rethinking and redesigning
of class and method structures. Most commonly,the effect is that classes are
split in two or that methods are divided into two or more methods.
Refactoring
can also include the joining of multiple classes or methods into one, but that
is less
common than
splitting.
Ø
Refactoring
and testing:
Before we
provide an example of refactoring, we need to reflect on the fact that, when we
refactor a
program, we are usually proposing to make some potentially large changes to
something
that
already works. When something is changed, there is a likelihood that errors
will be
introduced.
Therefore, it is important to proceed cautiously; and, prior to refactoring, we
should establish that a set of tests exists for the current version of the
program. If tests do not exist, then we should first decide how we can
reasonably test the functionality of the program and record those tests (for
instance, by writing them down) so that we can repeat the same tests later.
Refactoring
will follow the following two steps:
■ The first step is to refactor in
order to improve the internal structure of the code, but without
making any changes to the
functionality of the application. In other words, the program should,
when executed, behave exactly as
it did before. Once this stage is completed, the previously
established tests should be
repeated to ensure that we have not introduced unintended errors.
■ The second step is taken only once
we have reestablished the baseline functionality in the refactored version.
Then we are in a safe position to enhance the program. Once that has been
done, of course, testing will need
to be conducted on the new version.
Doing good refactoring is as
much about thinking in a certain mindset as it is about technical skills. While
we make changes and extensions to applications, we should regularly question whether
an original class design still represents the best solution. As the
functionality changes, arguments for or against certain designs change. What
was a good design for a simple application might not be good any more when some
extensions are added.
Recognizing
these changes and actually making the refactoring modifications to the source
code
usually saves a lot of time and effort in the end. The earlier we clean up our
design, the
more work
we usually save.
Ø
Refactoring
for language independence:
If we want to have language
independence in the program, then ideally we should have just one place in the
source code where the actual text of command words is stored and have
everywhere else refer to commands in a language-independent way. A programming
language feature that makes this possible is enumerated types, or enums.
In its simplest form, an enumerated
type definition consists of an outer wrapper that uses the word enum rather
than class and
a body that is simply a list of variable names denoting the
set of
values that belong to this type. By convention, these variable names are fully
capitalized.
We never
create objects of an enumerated type. In effect, each name within the type
definition
represents
a unique instance of the type that has already been created for us to use. We
refer to these instances as CommandWord.GO,
CommandWord.QUIT,
etc. Although the syntax for using them is similar, it is important to avoid
thinking of these values as being like the numeric class constants Despite the
simplicity of their definition, enumerated type values are proper objects and
are not the same as integers.
SUMMARY
Ø
Good class design can make a huge
difference when an application needs to be corrected, modified,or extended. It
also allows us to reuse parts of the application in other contexts (for
example, for other projects) and thus creates benefits later.
Ø
There are two key concepts under which
class design can be evaluated: coupling and cohesion.
Ø
Coupling refers to the
interconnectedness of classes, cohesion to modularization into appropriate
units. Good design exhibits loose coupling and high cohesion.
Ø
One way to achieve a good structure is
to follow a process of responsibility-driven design. Whenever we add a function
to the application, we try to identify which class should be responsible for
which part of the task.
Ø
When extending a program, we use
regular refactoring to adapt the design to changing requirement and to ensure
that classes and methods remain cohesive and loosely coupled.
CONCEPT
SUMMARY
■ Coupling The term coupling describes
the interconnectedness of classes. We strive for loose
coupling in a system—that is, a
system where each class is largely independent and communicates with other
classes via a small, well-defined interface.
■ Cohesion The term cohesion describes
how well a unit of code maps to a logical task or entity.In a highly
cohesive system, each unit of code (method, class, or module) is
responsible
for a well-defined task or entity.
Good class design exhibits a high degree of cohesion.
■ Code duplication Code duplication (having
the same segment of code in an application more
than once) is a sign of bad
design. It should be avoided.
■ Encapsulation Proper encapsulation in
classes reduces coupling and thus leads to a better
design.
■ Responsibility-driven design Responsibility-driven
design is the process of designing
classes by assigning well-defined
responsibilities to each class. This process can be used to
determine which class should
implement which part of an application function.
■ Localizing change One of the main goals of a
good class design is that of localizing change:
making changes to one class should
have minimal effects on other classes.
■ Method cohesion A cohesive method is
responsible for one, and only one, well-defined task.
■ Class cohesion A cohesive class
represents one well-defined entity.
■ Refactoring Refactoring is the activity of
restructuring an existing design to maintain a good
class design when the application
is modified or extended.
■ Switch statement A switch statement selects
a sequence of statements for execution from
multiple different options.