Re: Interface question
- From: "Bruce Wood" <brucewood@xxxxxxxxxx>
- Date: 13 Sep 2005 18:32:57 -0700
The choice between interfaces (which automatically imply
polymorphism... if you aren't using them in only one class then they
aren't terribly useful), inheritance polymorphism, and abstract classes
really has to do with the design of your class hierarchy.
This is the beauty of interfaces: you don't inherit from something
because "I need that functionality in my derived class". Well,
sometimes you do, just to be lazy (guilty). What you're supposed to do,
however, is inherit from a parent class because, in real-world terms,
what you're making "is a" specialized case of the parent class.
So, a Dog class would inherit from the Mammal class, because a Dog "is
a" Mammal. Or, you might have two types of PurchaseOrder: an
InternalPurchaseOrder and an ExternalPurchaseOrder. You arrange these
in an inheritance hierarchy because they are logically related.
So, in the case of the purchase orders, you can write code that deals
with PurchaseOrder in general, without worrying about whether it is an
InternalPurchaseOrder or an ExternalPurchaseOrder. Some of your code
will be that way: it won't matter which one you're dealing with. That's
inheritance polymorphism.
However, when you design these three classes, you have to ask yourself
if a PurchaseOrder is a "real" thing in your business: can you make
one, without it being internal or external? In some businesses, there
may be a third type of purchase order that is sort of a basic purchase
order, but in most businesses, the answer will be "no". So, you make
PurchaseOrder abstract: it's an artifact of your class hierarchy... it
doesn't represent a real business object. You need it, because an
InternalPurchaseOrder "is _not_ a" ExternalPurchaseOrder, and an
ExternalPurchaseOrder "is _not_ a" InternalPurchaseOrder, but you still
want them to be related, so you make this fake ("abstract") class that
is the "parent" of them both, so you can, in some of your code, treat
them as equivalent. That's polymorphism through abstract classes.
So, the difference between those two is whether the parent class is
something that logically exists in its own right, or is just a
side-effect of the way you want to arrange your class hierarchy.
Interfaces come into play when the classes you want to treat as
equivalent for some purposes have _nothing_ in common as far as the
class hierarchy is concerned. The only thing they have in common is
that they all offer the same functionality. So, rather than building a
tortured class hierarchy to try to make all of these classes have a
common parent where you can put the functionality, you declare an
interface, and make all of the classes implement it. Then you can write
code that treats the classes as equivalent.
For example, I just built a special kind of ListView, and a special
kind of Panel in WinForms. They are both backed by something called a
ListViewModel, which is the brains behind managing item selection,
sorting, etc. However, I can't have both of these classes inherit from
a common ancestor: they have to inherit from ListView and Panel,
respectively.
That wasn't a problem up until this week, when I decided that I wanted
to make another control that could interact with any control that was
backed by a ListViewModel. Now, suddenly, I have a class that wants to
treat these other two classes (and any others I may build) as
equivalent, but they have no common ancestor (that I can modify). So, I
created an interface called IHasListViewModel, with one property:
Model. Now I can write my new control to search for and interact with
any control that implements the IHasListViewModel interface, and it
will know that it can get the model and talk to it, because any control
implementing that interface has to have a ListViewModel behind it.
Notice that, in a single-inheritance language like C#, that was the
_only_ way to solve the problem, other than the totally gross solution
of having my new control know, explicitly, about every class I make
that has ListViewModel, like this:
if (aControl is ListViewForSelfKeyedCollection)
{
ListViewForSelfKeyedCollection lv =
(ListViewForSelfKeyedCollection)aControl;
}
if (aControl is ProfileImageGallery)
{
ProfileImageGallery pig = (ProfileImageGallery)aControl;
}
if (aControl is LabelForSelfKeyedCollection)
{
... etc.
Ewwww... yuck. Now I have to modify my little helper control every time
I add a new one of these. Gross. With the interface, I just say:
if (aControl is IHasListViewModel)
{
IHasListViewModel lvm = (IHasListViewModel)aControl;
ListViewModel model = lvm.Model;
... off to the races ...
}
Much better, no?
.
- Prev by Date: Re: OutOfMemoryException when using MessageQueueTransaction
- Next by Date: Re: Singleton Pattern and Collections
- Previous by thread: Re: Interface question
- Next by thread: aspx page going to top after refresh
- Index(es):
Relevant Pages
|