Titel   Inhalt   Suchen   Index   API  Go To Java 2, Zweite Auflage, Handbuch der Java-Programmierung
 <<    <     >    >>  Kapitel 9 - OOP III: Interfaces

9.5 Interfaces und Hilfsklassen



In den vorigen Abschnitten wurde gezeigt, daß es viele Gemeinsamkeiten zwischen (abstrakten) Klassen und Interfaces gibt. Während der Designphase eines komplexen Softwaresystems ist es daher häufig schwierig, sich für eine von beiden Varianten zu entscheiden. Für die Verwendung des Interfaces spricht die größere Flexibilität durch die Möglichkeit, in unterschiedlichen Klassenhierarchien verwendet zu werden. Für die Verwendung einer Klasse spricht die Möglichkeit, bereits ausformulierbare Teile der Implementation zu realisieren und die Fähigkeit, statische Bestandteile und Konstruktoren unterzubringen.

Wir wollen in diesem Abschnitt zeigen, wie sich beide Ansätze vereinen lassen. Dabei wird zunächst jeweils ein Interface zur Verfügung gestellt und seine Anwendung dann unter Verwendung einer Hilfsklasse vereinfacht.

9.5.1 Die Default-Implementierung

Wird ein Interface erstellt, das voraussichtlich häufig implementiert werden muß und/oder viele Methoden definiert, ist es sinnvoll, eine Default-Implementierung zur Verfügung zu stellen. Damit ist eine Basisklasse gemeint, die das Interface und alle sinnvoll realisierbaren Methoden implementiert. Besitzt eine Klasse, die das Interface implementieren muß, keine andere Vaterklasse, so kann sie von der Default-Implementierung abgeleitet werden und erbt so bereits einen Teil der sonst manuell zu implementierenden Funktionalität.

Als Beispiel soll ein Interface SimpleTreeNode definiert werden, das zur Konstruktion eines Baums verwendet werden kann, dessen Knoten von beliebigem Typ sind und jeweils beliebig viele Kinder haben:

001 /* SimpleTreeNode.java */
002 
003 public interface SimpleTreeNode
004 {
005   public void addChild(SimpleTreeNode child);
006   public int getChildCnt();
007   public SimpleTreeNode getChild(int pos);
008 }
SimpleTreeNode.java
Listing 9.15: Das SimpleTreeNode-Interface

Die Default-Implementierung könnte wie folgt realisiert werden:

001 /* DefaultTreeNode.java */
002 
003 public class DefaultTreeNode
004 implements SimpleTreeNode
005 {
006   private int              CAPACITY;
007   private String           name;
008   private SimpleTreeNode[] childs;
009   private int              childcnt;
010 
011   public DefaultTreeNode(String name)
012   {
013     this.CAPACITY = 5;
014     this.name     = name;
015     this.childs   = new SimpleTreeNode[CAPACITY];
016     this.childcnt = 0;
017   }
018 
019   public void addChild(SimpleTreeNode child)
020   {
021     if (childcnt >= CAPACITY) {
022       CAPACITY *= 2;
023       SimpleTreeNode[] newchilds = new SimpleTreeNode[CAPACITY];
024       for (int i = 0; i < childcnt; ++i) {
025         newchilds[i] = childs[i];
026       }
027       childs = newchilds;
028     }
029     childs[childcnt++] = child;
030   }
031 
032   public int getChildCnt()
033   {
034     return childcnt;
035   }
036 
037   public SimpleTreeNode getChild(int pos)
038   {
039     return childs[pos];
040   }
041 
042   public String toString()
043   {
044     return name;
045   }
046 }
DefaultTreeNode.java
Listing 9.16: Default-Implementierung des SimpleTreeNode-Interfaces

Der Vorteil ist hier noch nicht sehr offensichtlich, weil die Implementierung nicht sehr aufwendig ist. Bei komplexeren Interfaces zahlt es sich in der Praxis meistens aus, wenn eine Default-Implementierung zur Verfügung gestellt wird. Neben der dadurch erzielten Arbeitsersparnis nützt sie auch zur Dokumentation und stellt eine Referenzimplementierung des Interfaces dar.

 Hinweis 

9.5.2 Delegation an die Default-Implementierung

Läßt sich eine potentielle SimpleTreeNode-Klasse nicht von DefaultTreeNode ableiten, muß sie das Interface selbst implementieren. Besitzt die Default-Implementierung bereits nennenswerte Funktionalitäten, wäre es schlechter Stil (und auch sehr fehlerträchtig), diese ein zweites Mal zu implementieren. Statt dessen ist es eventuell möglich, die Implementierung an die bereits vorhandene DefaultTreeNode zu delegieren.

Dazu muß die zu implementierende Klasse eine Membervariable vom Typ DefaultTreeNode anlegen und alle Aufrufe der Interface-Methoden an dieses Objekt weiterleiten. Soll beispielsweise die Klasse Auto aus Listing 7.1 in eine SimpleTreeNode verwandelt werden, könnte die Implementierung durch Delegation wie folgt vereinfacht werden:

001 /* Auto5.java */
002 
003 public class Auto5
004 implements SimpleTreeNode
005 {
006   public String name;
007   public int    erstzulassung;
008   public int    leistung;
009 
010   private SimpleTreeNode treenode = new DefaultTreeNode("");
011 
012   public void addChild(SimpleTreeNode child)
013   {
014     treenode.addChild(child);
015   }
016 
017   public int getChildCnt()
018   {
019     return treenode.getChildCnt();
020   }
021 
022   public SimpleTreeNode getChild(int pos)
023   {
024     return treenode.getChild(pos);
025   }
026 
027   public String toString()
028   {
029     return name;
030   }
031 }
Auto5.java
Listing 9.17: Implementierung des SimpleTreeNode-Interfaces durch Delegation

Hier nutzt die Klasse Auto5 die Funktionalitäten der Membervariable DefaultTreeNode zur Verwaltung von Unterknoten und leitet alle entsprechenden Methodenaufrufe an sie weiter. Die Verwaltung des Knotennamens erfolgt dagegen mit Hilfe der eigenen Membervariable name.

9.5.3 Die leere Implementierung

Mitunter wird ein Interface entworfen, bei dem nicht immer alle definierten Methoden benötigt werden. In der Java-Klassenbibliothek gibt es dafür einige Beispiele, etwa bei Listenern (siehe Kapitel 28) oder im Collection-API (siehe Kapitel 15). Da bei der Implementierung aber immer alle definierten Methoden implementiert werden müssen, wenn die Klasse nicht abstrakt bleiben soll, kann es nützlich sein, eine leere Standard-Implementierung zur Verfügung zu stellen. Implementierende Klassen können sich dann gegebenenfalls von dieser ableiten und brauchen nur noch die Methoden zu realisieren, die tatsächlich benötigt werden.


 Titel   Inhalt   Suchen   Index   API  Go To Java 2, Zweite Auflage, Addison Wesley, Version 2.0
 <<    <     >    >>  © 2000 Guido Krüger, http://www.gkrueger.com