Gamma et al
describe the Abstract Factory Pattern,
which is useful
for "a user interface toolkit that supports
multiple
look-and-feel standards, such as Motif and
Presentation
Manager" [6]. ET++ [17] used the same
pattern to
achieve portability across different window
systems. In the
Abstract Factory Pattern, each user
interface item
is defined as an abstract class, and the
various
implementations (in this example, Motif and
Presentation
Manager) are defined as children of the
abstract class.
Then, a factory is defined. The factory
merely calls the
appropriate creation methods
depending on
which implementation is currently
selected.
Matthew Heaney [9] has implemented the
Abstract Factory
Pattern in Ada in two ways. The first
is exactly as
described by Gamma et al; he also notes
that you can
accomplish the Abstract Factory simply by
doing static
package renaming. Figure 1 shows the
class hierarchy
of the Abstract Factory Pattern obtained
from the SIGAda
Patterns web site [9]. The triangular
arrows point
from a child class to its parent class. The
dashed lines
point from a client to the package whose
objects it
instantiated. The solid arrows point from a
client to the
packages it utilizes. Although it is not
shown in the
diagram, the client would also need to
access
AbstractProduct1 and AbstractProduct2 to use
the associated
methods.
The problem with
the Abstract Factory Pattern becomes
evident when we
attempt to extend an abstract product.
For example,
suppose we wish to create
AbstractProduct3,
which extends the functionality of
AbstractProduct2. It
is a simple matter to create the
abstract class,
by simply extending AbstractProduct2.
When we
implement Product31, it is likely the case that
we would like to
extend the class Product21.
Unfortunately,
Product31 is already a child of
AbstractProduct3.
Many important object-oriented
languages (such
as Ada and Java) do not allow multiple
inheritance;
therefore, we are required to reimplement
the
functionality of Product21 in Product31.
One solution is
to simply dispose of the Abstract
Factory
altogether, and implement two separate
hierarchies,
making sure that each has the same
methods and
class names. The user then selects an
implementation
by including the appropriate set of files
in the project
(via a makefile, compiler flags, or
similar). This
has the disadvantage that multiple copies
of the
specifications are created, each differing only in
the
representation of the data.
We instead solve
the problem by creating the