|
Some programmers are lucky - they studied Object Oriented
Programming (OOP) in college, or were personally tutored by a master programmer,
or were just plain so smart that somehow they started out OOPing and never
had to change their perfect ways. Folks like me, who wrote their first
programs in Applesoft BASIC on PC's with 64K of RAM, aren't that lucky.
We had to learn it mostly via the brute force approach which usually mostly
involves "unlearning" all the bad programming habits we used
to think were so great.
Now that .NET is making its mark on the hearts and minds
of programmers and their clients worldwide, it might be prudent for all
of us whether we are VB.NET, C#, Eiffel or Perl programmers, to revisit
OOP and try to spend more time understanding how it can help us solve
the problems of the world.
So let's first recap the three "Pillars of OOP",
presented as my personal "take" on it:
1) OOP is Encapsulation:
Hiding Data, but defining properties and methods to let the caller have
access to it. OOP succeeds only when you manipulate data inside objects,
only sending requests to the object. This "Data Hiding" is critical
to both successful reuse and long-term reliability of components.
2) OOP is Inheritance:
The concept of deriving classes from a base class where the derived class
"is a" one of the base class (e.g. a Manager "is a"
Employee). Inherited classes are always more specialized than their base
(parent) classes, have at least as many members (although the behavior
of individual members may be different) and often have new methods
that have no counterpart in the base class. There are various types of
inheritance. Interface inheritance inherits only the
interface signature, while implementation inheritance
inherits the actual code implemented in its parent. Another subset of
Inheritance, and often referred to as the fourth "Pillar of OOP"
is Aggregation, where the method of an inner component
is to be directly exposed to the outside world. An object takes the inner
object’s interface, and presents it as it's own. In my short article
here entitled "Got
Interface?" I describe some of the features of this technique.
3) OOP is Polymorphism:
This is the concept where inherited objects "know" what methods
they should use, depending on their position in the inheritance chain.
An "Account" object will know that if it is a PremiumAccount
object, it must call the GetCashAdvance method in the PremiumAccount class
rather than the one in the Account class. You do not need to know what
class an object actually belongs to in the inheritance chain when you
send it a request; you can just send all Account objects the same GetCashAdvance
message and each Account object will automatically choose the correct
polymorphic method in each object.
Object Oriented Programming is really a lot more than a “programming
concept". It’s a way of learning to think
in a completely new way about the process of how to design
and create robust, scalable applications. With OOP, we learn to think
of applications not as "sets of procedures and properties",
but as objects and “beings” that are logically grouped by
the way they appear, behave and function. Financial Accounts, for example,
may differ in type, features, privileges and requirements, yet they’re
all similar in form and function - they could all derive from the same
base Account class. Coding in an object-oriented manner follows this model
and, above all, it takes advantage of the ability to build on it.
The fact that code we write may contain properties and methods doesn't
make it "object oriented". That COM component
we wrote in VB 6.0 may contain functions that perform calculations and
retain values. This component may be referred to as an "object"
in the strict sense because it is an instance of a class, but it may very
well not be object-oriented at all if it does not follow the principles
of OOP. It's up to us to revisit that
component as we get ready to migrate it to the .NET platform, and refactor
the code to conform to and take advantage of OOP principles.
The key thing to keep in mind when unlearning all the procedural programming
thinking we've developed is that in OOP "everything is an object".
In an object-oriented approach to Bank Accounts we'll have an Account
object, and we'll send a message to that object to ask it for it's current
total balance or to make a deposit. We don't need to think about how the
information is stored internally in the object, as we had to do with our
non-object-oriented data structures. We just make requests to it by sending
messages. The Account object probably iterates through a collection of
detail objects, sending a message to each one requesting its current balance
and probably making some specialized computations dependent on the particular
Account features. However, if what we're looking for is the total, we
don't care how it's done, because one of the primary tenets of object-oriented
programming is encapsulation—the ability of an
object to hide its internal data and methods and to present an interface
that makes the important parts of the object programmatically accessible.
We accomplish this by only allowing an object's methods to modify it's
variables.
The key way our encapsulation is preserved is through the object's interface
( the methods and properties the users of our class can see). If you can
develop a stable, static interface that persists across implementation
changes, less of your application will need modification over time. This
means, very simply, that If you really understand the problem domain of
an application, you can determine to a fairly high degree the methods
that the users of this class are going to need. You need to be able to
combine expert knowledge of the problem domain with forethought and planning
in the design of your class. If we can acommplish this, then we can be
reasonably sure that the majority of our interface for this class will
remain unchanged despite any future changes in the actual implementation
of the class.
The next question that should enter our minds is "How do I go about
OOPifying my program?" Here's a concise outline of the steps, in
greatly simplified form:
1) In OOP, you first isolate the potential classes
(which are usually the "nouns" in your programming problem).
Only then do you look for the methods and properties
of the class. The methods normally correspond to the "verbs"
in your programming problem, and the properties are usually the "adjectives".
2) You then associate each method or property with the class that is
responsible for carrying out the operation (or create a new class to do
so if one has not already been created).
3) You need to identify the state, identity, and behavior of each individual
object (instance of one of the classes in your project). These properties
can all change over time even though the instances may seem to be "Identical".
In Visual Basic (where most of us are coming from) , we use classes to
define components. Once a class is created and populated it becomes an
object with properties and methods. However at this point all we've accomplished
is to prove that Visual Basic can do classes with properties and methods.
OOP presents a major paradigm shift especially for VB programmers who've
been so blissfully insulated even from the inner workings of the COM infrastructure
over the last 5 years, much less having been exposed to OOP techniques,
which on the whole, classic VB simply does not support. Sure, you can
get ahold of Visual Studio.NET and start writing code that will compile
- code that is similar in it's old-style procedural programming techniques
to the Visual Basic or other code you have become familiar with. But,
you'd be missing the "OOP boat", so to speak. It's like driving
an Aston Martin and never learning to get it out of second gear...
OOP is a whole way of looking at the technique of solving business problems
in a reusable, extendable and performance-oriented way. It's something
that doesn't come easily. It takes lateral thinking, something which Americans
in particular aren't familiar with. Fortunately, there are lots of resources
available in books and on the NET to help programmers move quickly into
this modality and begin to reap its benefits in the form of better and
more productive code, promotion of code reuse throughout the development
organization, and faster time to market in solving complex business problems.
Peter Bromberg is an independent consultant specializing in distributed .NET solutions
in Orlando and a co-developer of the EggheadCafe.com
developer website. He can be reached at pbromberg@yahoo.com |