next up previous contents index
Weiter: 12.3 Iteratoren Hinauf: 12 Objektorientierte Konzepte Zurück: 12.1 Heterogene Listen

12.2 Mehrfache Implementationen

Obwohl schon häufig erkannt worden ist, daß es sehr sinnvoll ist, zu einer Abstraktion mehrere Implementation schaffen zu können, die auf unterschiedliche Eigenschaften der Objekte eingehen, wie zum Beispiel dicht oder dünn besetzte Matrizen, war ein solches Vorgehen erstmals in C++ möglich. Nun bietet auch Ada diese Möglichkeit.

Eine Spezifikation eines abstrakten Mengen-Paketes könnte etwa wie folgt aussehen.


package Abstract_Sets is

type Set is abstract tagged private;

-leereMenge
function Empty return Set is abstract;

-AufbaueneinerMengemiteinemElement
function Unit(Element: Set_Element) return Set is abstract;

-VereinigungvonMengen
function Union(Left, Right: Set) return Set is abstract;

-DurchschnittzweierMengen
function Intersection(Left, Right: Set) return Set is abstract;


-EntferneneinesbeliebigenElementsausderMenge
procedure Take(
From: in out Set;
Element: out Set_Element) is abstract;

Element_Too_Large: exception;

private

type Set is abstract tagged null record;

end Abstract_Sets;

Der Set-Typ ist ein abstrakter getaggter privater Typ, dessen interne Darstellung ein Null-Record ist. Für ihn ist eine Reihe von primitiven Operationen in Form von abstrakten Unterprogrammen definiert. Diese können natürlich nicht direkt aufgerufen werden, aber sie können sehr wohl vererbt und umdefiniert werden. Abgeleitete Typen von Set müssen dann ihre eigenen Implementierungen schaffen.

Ein Beispiel für so einen abgeleiteten Typ ist folgender.


with Abstract_Sets;
package Bit_Vector_Sets is

type Bit_Set is new Abstract_Sets.Set with private;

-neueDefinitionderOperationen
function Empty return Bit_Set;
function Unit(Element: Set_Element) return Bit_Set;
function Union(Left, Right: Bit_Set) return Bit_Set;
function Intersection(Left, Right: Bit_Set) return Bit_Set;

procedure Take(From: in out Bit_Set;
Element: out Set_Element);

private
Bit_Set_Size: constant integer := 64;
type Bit_Vector is
array (Set_Element range 0 .. Bit_Set_Size-1) of Boolean;
pragma Pack(Bit_Vector);

type Bit_Set is new Abstract_Sets.Set with
record
Data: Bit_Vector;
end record;
end Bit_Vector_Sets;


package body Bit_Vector_Sets is

function Empty return Bit_Set is
begin
return (Data => (others => False));
end;

function Unit(Element: Set_Element) return Bit_Set is
S: Bit_Set := Empty;
begin
S.Data(Element) := True;
return S;
end;

function Union(Left, Right: Bit_Set) return Bit_Set is
begin
return (Data => Left.Data or Right.Data);
end;

...

end Bit_Vector_Sets;

Eine alternative Implementierung für dünn besetzte Mengen könnte dann eine Listenverwaltung der Elemente verwenden.


with Abstract_Sets;
package Linked_Sets is

type Linked_Set is new Abstract_Sets.Set with private;

-neueDefinitionderOperationen
function Empty return Linked_Set;
function Unit(Element: Set_Element) return Linked_Set;
function Union(Left, Right: Linked_Set) return Linked_Set;
function Intersection(Left, Right: Linked_Set) return Linked_Set;

procedure Take(From: in out Linked_Set;
Element: out Set_Element);

private
type Element;
type Element_Ptr is access all Element;
type Element is
record
the_Element: Set_Element;
the_next: Element_Ptr;
end record;
type Linked_Set is new Abstract_Sets.Set with
record
first_Element: Element_Ptr;
end record;
end Linked_Sets;


package body Linked_Sets is

function Empty return Linked_Set is
begin
return (first_Element => null);
end Empty;
function Unit(Element: Set_Element) return Linked_Set is
S: Linked_Set;
begin
S.first_Element := new Element'(Element,null);
return S;
end Unit;

...

end Linked_Sets;

Wir können dann ein Programm schreiben, das beide Formen von Mengen gleichzeitig verwendet, und wir können eine Konversion zwischen den beiden Darstellungen wie folgt durchführen.


procedure Convert(From: in Set'Class; To: out Set'Class) is
Temp: Set'Class := From;
Elem: Set_Element;
begin
-builduptargetset,oneelementatatime
To := Empty;
while Temp Empty loop
Take(Temp, Elem);
To := Union(To, Unit(Elem));
end loop;
end Convert;

Dabei ist zu beachten, daß der Dispatching-Mechanismus voll zur Wirksamkeit gelangt.

Abschließend sei noch darauf hingewiesen, daß das abstrakte Set-Paket auch generisch sein könnte, was die Wiederverwendbarkeit des Paketes noch steigern würde.



next up previous contents index
Weiter: 12.3 Iteratoren Hinauf: 12 Objektorientierte Konzepte Zurück: 12.1 Heterogene Listen

Johann Blieberger
Wed Feb 11 09:58:52 MET 1998