Vous êtes sur la page 1sur 3

Abstract Classes vs.

Interfaces
If you are familiar with interfaces, you may be thinking that an abstract class does
much the same thing. This is only partly true. Defining an abstract class that
contains only abstract members has essentially the same effect as defining an
interface, because you specify that derived classes must implement certain members
with specific signatures. Beyond this, however, abstract classes provide additional
capabilities—specifically, the definition of base functionality in the form of non-
abstract members, something that an interface cannot do.

When you think that either an abstract class or an interface would work, keep these
considerations in mind:

A derived class can implement multiple interfaces, but can inherit from only one class
(abstract or not).

A class that subclasses an abstract class can still implement one or more interfaces.
Depending on the needs of your project, you may rely on a single abstract class, one
or more interfaces, or a combination of an abstract class with an interface. Visual
Basic and .NET provide a great deal of flexibility in this regard, and you can often
achieve the same result in more than one way. The bottom line is that there are
some things that just cannot be done without using an abstract class. Abstract
classes may be thought of as a rather specialized programming tool. When the
situation calls for it, they reduce the developer's work and lead to a simpler, more
robust application.

An Abstract Class in Action


Imagine developing a new employee records system for a large multinational
corporation. Your job is to supervise the implementation of classes to represent
employees such that certain core requirements of the head office are met, while still
providing flexibility for differing requirements from company branches elsewhere.

The core requirements are as follows:

Name and DateOfHire properties will be implemented in the abstract class and
cannot be overridable.

Interface types
Programming with interfaces types is an extremely powerful concept. Object-oriented
programmers are familiar with the concept of substituting a derived type for a base
type. However, sometimes two classes are not related by inheritance, but they do
share common functionality. For example, many classes may contain methods for
saving their state to and from permanent storage. For this purpose, classes not
related by inheritance may support common interfaces, allowing programmers to
code for the classes' shared behavior based on their shared interface type and not
their exact types.

An interface type is a partial specification of a type. It is a contract that binds


implementers to provide implementations of the methods contained in the interface.
Object types may support many interface types, and many different object types
would normally support an interface type. By definition, an interface type can never
be an object type or an exact type. Interface types may extend other interface types.

An interface type may contain:

Methods (both class and instance)


Static fields
Properties
Events
A major difference between an interface type and an object type (or a value type
class) is that an interface type cannot contain instance fields.

The following code demonstrates a user-defined interface type, "IPoint." This


interface type declares two attributes (requiring four accessor methods in any
implementor). By inheriting from IPoint, the class Point agrees to implement these
four abstract methods. The remainder of the definition of the class Point remains
unchanged from that in the code in the Reference Types section.

#using <mscorlib.dll>

using namespace System;

__gc __interface IPoint


{
__property int get_X();
__property void set_X(int value);
__property int get_Y();
__property void set_Y(int value);
};

__gc class Point: public IPoint


{
...
};

The common language runtime provides a number of interface types. The following
code demonstrates the use of the IEnumerator interface supported by array objects.
The array of Point*s allows clients to enumerate over the array by requesting an
IEnumerator interface. The IEnumerator interface supports three methods:

Current. Returns the current object.


MoveNext. Moves the enumerator on to the next object.
Reset. Resets the enumerator to its initial position.
int main(void)
{
Point *points[] = new Point*[5];
for(int i = 0, length = points->Count; i < length; i++)
{
points[i] = new Point(i, i);
}
Collections::IEnumerator *e = points->GetEnumerator();
while(e->MoveNext())
{
Object *o = e->Current;
Point *p = dynamic_cast<Point*>(o);
Console::WriteLine(p->X);
}
return 0;
}

Array objects support many other useful methods, such as Clear, GetLength, and
Sort. Array objects also provide support for synchronization. Synchronization is
provided by methods such as IsSynchronized and SyncRoot.

A RetirementID property will be implemented in the abstract class to handle Social


Security numbers because most employees live in the United States. Branches in
other countries will use different ways to identify an employee's retirement
identification, so this property will be overridable in derived classes to permit
individual branches to implement it differently as required.

A method called Compensation will take no arguments and will return a type Object
containing details of the employee's compensation. Because compensation—salary,
commissions, bonuses, and so on—are handled differently at the various branches,
complete flexibility in implementing this method is necessary; it will be made an
abstract method.
The code for the resulting abstract class, called EmployeeBase, is shown in Listing 1.
You'll see that I've omitted the actual implementation of the base members because
those details are not relevant here.

At the company office in Paris, France, a programmer is using the EmployeeBase


class as the basis for the EmployeeFrance class (see Listing 2) to use with the local
employee records software. This derived class will necessarily inherit the Name and
DateOfHire members. Furthermore, the RetirementID member in the EmployeeBase
class is suitable for use in France, so the new class will not override it. All that the
programmer has to do is implement a method to override the abstract Compensation
member.

In London, England, however, the base class's RetirementID property is not suitable,
so the derived class (called EmployeeEngland, shown in Listing 3) will override that
member as well as the Compensation member. The implementation of Compensation
will likely be different from the one used in France.

Vous aimerez peut-être aussi