Object Orientation Principles / Best Practices
Whilst the vary to which these principles are supported by
different languages vary, there are a certain set of principles to the
OO paradigm which I hope to 'encapsulate' here. This page largely
serves as a definition of terms and may be refered to from other
documentation.
- Encapsulation
- The attributes and services/behaviors are encapsulated in a
class. No direct access of an object's properties happens from
outside the code associated with that class.
- Information Hiding
- The information that an object uses to drive its implementation
are not visible from the "outside". This is usually not enforced
with Perl.
- Certain attributes and services may be internal to the class
(private), the package (protected), or external (public). Again,
these are distinctions not normally enforced in Perl.
- Message Passing
- Objects communicate by invoking services from other objects,
passing the required information for the service. This means that
even if an operation is thought to be happening between two
objects of the same type, they must still communicate with each
other through their "formal" interface.
- An Object Oriented Surgeon would hand you a scalpel and say,
“Now perform this operation on yourself!”.
- Late Binding
- An object is not linked to it's behaviors until run-time. This
is important for polymorphism. In Perl 5, all method lookups are
always bound (or verified) at run time.
- Delegation
- Objects may pass work on to other objects and behave as those
delegated objects.
- Class/Instance/Object
- All objects are instances of a class.
Objects which are similar enough to share the same implementation
of methods are usually considered to share a common class, or be
of the same "type".
- This is not a hard and fast rule; it may also be possible for
individual objects to be able to behave as two classes of object
simultaneously. This is commonly called a mix-in, and
the varieties of levels of this are called Roles in Perl
6. However, this functionality is only syntactically different
from delegation.
- Generalization/Specialization without Polymorphism
- Classes may inherit attributes and services from another class,
and behave exactly as the parent class. The test for this is
called the empty sub-class test, where a new class is
created that is a degenerately void specialisation of the parent
class. The object should still behave exactly as if it were a
member of the parent type.
- Generalization/Specialization with Polymorphism
- A class may override methods inherited from a
superclass. Polymorphism allows the language to call the
correct method in the hierarchy. As well as polymorphism, there
must be some method of calling superclass methods, so
that you can augment, and not merely replace functionality.
-
- Relationships (or Associations)
- An object may be composed of other objects, which determine how
it behaves. For example, a car is composed of body, engine,
suspension, etc.; and these in turn are also composed of simpler
objects. The major commonly recognised forms of relationships are
associations, aggregations and
compositions. The differences between them may appear to
be minor, but a clear distinction between them whilst designing
programs can be useful.
- Interface/Implementation
- An object may be of a type declared by an interface.
That is, it does not provide an implementation that may be
sub-classed; it simply prescribes a set of operations and they
must be fully implemented by the provider of the
interface.
- Generalization/Specialization of Interfaces
- A class may implement the methods of multiple interfaces at
once. These interfaces should not place any undue restrictions on
other specialization that the object may perform.
- Reflection (aka Run-Time Type Information)
- Each object knows the details about which class or interface of
which it is a member. This is sometimes called “Run Time Type
Inspection”, and is possible to do with Class::Tangram - in fact,
this is used extensively in the interactive T2 schema browser.
- Multithreading
- Each object can have multiple concurrent execution paths. In
practice, this means keeping all state information about what you
are doing with an object on the stack (as the stack is never
shared between threads), and committing changes back to the object
in a "safe" fashion - that is, never leaving the object in a state
where another thread reading the object might get confused.
References
Source material used for this page include:
- Principles of Object Orientation [now offline]
http://www.math.grin.edu/~bishopd/csc223/Principles_of_Object_Orientation.html
- Object Orientation, from OutBack Software (Aus)
http://www.outbacksoftware.com/oo/oo.html
- “Years of experience” - Dr. Phil