In the object-oriented paradigm, one must constantly think about a

advertisement
Disciplined Approach to Design
An undisciplined ad hoc (“code now, think later or not at all”) approach can frequently be
used to solve complete self contained well defined problems. However when confronted
with more substantial, less well-defined problems – problems for which design issues
involving complex structural relations between components must be effectively
addressed – this undisciplined method flounders.
We must first create the appropriate model for the problem and only then we must devise
the appropriate realizable techniques to solve it.
System Design is fundamentally a science of generalization and specialization.
Generalization (or abstraction) is the process of ignoring details irrelevant to the problem
at hand and emphasizing essential ones. To abstract is to disregard certain differentiating
details and recognize certain commonalities. To specialize is to concentrate on the
variation in the details.
In the object-oriented paradigm, one must constantly think about a problem from three
different levels of perspective.
1. The Conceptual level perspective concerns the concepts in the domain under
study
2. The Specification level perspective concerns the interfaces of the software, not the
implementation
3. The Implementation level perspective concerns the code itself.
The Implementation perspective is the most used but in many ways the Conceptual
perspective and the Specification perspective are the most important.
At the Implementation level, an object is just code and data.
At the Specification level, an object is a set of methods that can be invoked by other
objects or by itself. The set of these methods define the objects public interface.
At the Conceptual level, an object is an entity with responsibilities. Specifically
objects are responsible for themselves. These responsibilities give the object its
behavior.
The conceptual approach helps us focus on what the objects are supposed to do, not
simply on how to implement them. This also means we can design an object without
worrying about all of the details involved. By focusing on what an object does,
inheritance allows us to use different, specific behaviors when needed.
It is easier to think in terms of responsibilities because that helps to define the
object’s public interface. If an object has a responsibility, there must be some way to
ask it to perform its responsibility.
Design towards the Specification (interface) perspective to see the overall picture and
to avoid being overwhelmed by details. In other words design the public interface
first before the actual implementation..
Design each component so that it is given its specific public interface only by its
existence in the context of the larger whole. When components are made without
regard to the whole it is impossible for every component to be unique, according to its
position in the whole.
Abstract classes are defined at the Implementation level as classes which are not
instantiated. This definition is accurate but too limiting.
At the Conceptual level abstract classes are simply placeholders for other classes.
They give us a way to assign a name to a set of related classes. This lets us treat this
set as one concept. Abstract classes define the methods (responsibilities) their derived
classes must implement. Abstract classes can also contain common methods that can
be used by all derivations. An abstract class allows one to refer to all of the related
classes/objects in a single consistent way yet each derived class will use the default
behavior or replace it with its own variation (this is consistent with the idea that
objects are responsible for themselves).
Having responsibilities does not imply anything about what is inside the object. The
information for which the object is responsible for may not even reside in the object
itself (it may reside on a database server). There are many things that do not need to
be exposed to other objects. This is the concept of encapsulation which is generally
described as simply hiding the internal data members of the class. But encapsulation
really refers to much more than data hiding. In general encapsulation means any kind
of hiding. It can hide data, implementations, derived classes, other objects, or
anything else that needs to be hidden.
The advantage of looking at encapsulation this way is that it gives us a better way to
split up a system. The encapsulating layers become the interfaces we design to.
Encapsulation creates layers between objects or parts of a system so that we can
change things on one side of a layer without adversely affecting the other side. This
promotes loose-coupling between the sides.
One important type of encapsulation is achieved when there is an abstract class that
behaves polymorphically without the client of the abstract class knowing what kind of
derived class actually is present. In this case encapsulation hides derived classes using
an abstract class.
Inheritance is usually presented as a way for reuse of existing classes by deriving new
classes from these base classes. This suggests a kind of top-down model in which we
start with a generalized class and then descend more specialized sub classes. This is
certainly true but inheritance becomes much more powerful when we regard it as an
important abstraction concept. Inheritance is better used as a method of consistently
dealing with different concrete classes that are conceptually the same rather than as a
means of specialization. This suggests a bottom-up model in which we start with a set
of (varying) subclasses and use abstraction to describe this set by an abstract
superclass which encapsulates the variance in the subclasses.
The technique is to find what is varying and encapsulate it. Consider what should be
variable in the system design. This approach is the opposite of focusing on the cause
of redesign. Instead of considering what might force a design change, consider what
we want to be able to change without redesign. The focus here is on encapsulating the
concept that varies. Using composition of a reference to an abstract class hides the
variations. The concept of using objects to hold variations in behavior is similar to the
practice of using data members to hold variations in data. Both allow for the
encapsulation (and therefore extension) of the data or behavior being contained.
Consider the diagram shown below.
Commonality
analysis
Conceptual
perspective
Specification
perspective
Variability
analysis
Abstract
classes
Concrete
classes
Implementation
perspective
Commonality analysis relates to the conceptual view of the problem domain and
variability analysis relates to the implementation, that is, to specific cases. The
specification perspective lies in the middle. Both commonality and variability are
involved in the specification perspective. The specification describes how to
communicate with a set of objects that are conceptually similar. Each of these objects
represents a variation of the common concept. This specification becomes an abstract
class or an interface at the implementation level.
The abstract class is the central binding concept. An abstract class represents the core
concept that binds together all of the derivatives of the class. This core concept is
what defines the commonality.
Commonality determines which abstract classes to use. The commonalities define the
abstract classes needed.
The variations determine the derivations of the abstract class. Variations identified
within that commonality become derivations of the abstract classes.
The specification determines the interface for abstract classes. The interface for these
classes corresponds to the specification level.
When defining an abstract class (commonality) we must ask what interface is needed
to handle all of the responsibilities of this class.
When defining derived classes we must ask given this particular realization (this
variation), how can we implement it within the given specification.
The relationship between the specification perspective and the conceptual perspective
is this: It identifies the interface we need to use to handle all of the cases of this
concept (that is, the commonality).
The relationship between the specification perspective and the implementation
perspective is this: Given this specification, how can we implement this particular
case (this variation).
Download