From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../hjp5/html/k100062.html | 318 +++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100062.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100062.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100062.html b/Master/Reference Architectures and Patterns/hjp5/html/k100062.html new file mode 100644 index 0000000..a3038cf --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100062.html @@ -0,0 +1,318 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 9 - OOP III: Interfaces +
+
+ + + + +

9.5 Interfaces und Hilfsklassen

+
+ +
+ +

+In den vorigen Abschnitten wurde gezeigt, dass 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 muss 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 muss, 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.16: 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.17: Default-Implementierung des SimpleTreeNode-Interfaces

+

+ + + + + + + + + +
+ +

+Der Vorteil ist hier noch nicht sehr offensichtlich, weil die Implementierung +nicht sehr aufwändig 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, +muss 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 muss 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.18: 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  + DOC  +Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 +
 <<  +  <   +  >   + >>  + API  +© 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de +
+ + + -- cgit v1.2.3