Fasko Geschrieben 5. November 2011 Teilen Geschrieben 5. November 2011 Hallo, also ich habe jetzt in einem Buch ein tolles Kapitel gelesen zum Thema Vererbung. Jedoch fehlten leider (vollständige) Praxis-Beispiele. Also wie wende ich das jetzt im Code an!? Folgendes habe ich ohne Erfolg probiert: Hauptprogramm: public class Testlauf { /** * @param args */ public static void main(String[] args) { Tier hier = new Tier(); int hallo = 2; int zahl; test(); Tier.ego(); zahl = Tier.binMethode(2); System.out.println(zahl); } public static void test() { System.out.println("Test"); System.out.println("Also... ich denke an eine Zahl, an "+ Tier.binMethode(4)+"!"); } } Klasse: public class Tier { String nahrung; int hunger; int grenzen; public static int binMethode(int wert) { System.out.println(wert); return wert+2; } public static void ego() { System.out.println("Ich sage nur Hallo, gebe dir aber sonst nichts!"); } } Klasse die erben soll von der Klasse Tier: public class Wolf extends Tier { ego(); // Tier.ego(); // Beide Zeilen werde rot unterkringelt :-( } Wie muss das richtig aussehen? Das viele Variablen mehr oder weniger nicht genutzt werden weiß ich. Ich habe das Programm nur zum probieren erstellt und scheitere direkt schon am Anfang. Gruß, Fasko Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
lilith2k3 Geschrieben 5. November 2011 Teilen Geschrieben 5. November 2011 Vererbung geschieht auf zweierlei Art und Weise (in Sprachen wie Java oder C#) durch Klassenvererbung oder durch Interfacevererbung. Es kommt immer darauf an, was Du modellieren willst. Willst Du eine Beziehung der Art A ist ein B modellieren wählst Du die Klassenvererbung. Ein Beispiel aus der Praxis wäre eine Klasse Logger. Man könnte verschiedene Arten von Loggern implementieren: File-Logger, Konsolen-Logger, Eventlogger, Datenbank-Logger. Insofern wäre es sinnvoll, zu bestimmen, was alle Logger können sollten. Daraus baust Du dann die (abstrakte) Basisklasse. Die davon abgeleiteten Methoden überschreiben dann die Methoden der Elternklasse. Willst Du etwas modellieren, was ausdrückt, dass A b kann, also die Fähigkeit besitzt etwas zu können, dann wählst Du die Interfacevererbung. Die Implementierung entscheidet dann das Verhalten. Auf unser Logger-Beispiel bezogen: Wenn wir uns die verschiedenen Logger-Arten vor Augen halten, so haben sie alle gemein, dass sie gewisse Loggingfähigkeiten voraussetzen. Diese kann man in einer Interfacedefinition festhalten und alle Objekte, die das entsprechende Interface implementieren, können untereinander ausgetauscht werden. Wenn ein Objekt beispielsweise den Anspruch hat, ein anderes Objekt zu empfangen, welches logging beherrscht, so ist es ihm piepschnurzegal, welches Objekt kommt und was das Objekt tut. Hauptsache das gewünschte Interface wird unterstützt. Je nach Anwendungsfall kannst Du das eine oder das andere Modell wählen. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Fasko Geschrieben 5. November 2011 Autor Teilen Geschrieben 5. November 2011 Ok, dann benötige ich die Interfacevererbung. Wie sähe das denn jetzt in einem Praxisbeispiel (Code) aus? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
lilith2k3 Geschrieben 5. November 2011 Teilen Geschrieben 5. November 2011 public interface Logging { void Debug(String message); void Warning(String message); void Error(String message); void Info(String message); } class ConsoleLogger implements Logging { public void Debug(String message) { //Konsolenausgabe } ... } class EventLogger implements Logging { public void Debug(String message) { //Ausgabe in's Eventlog } ... } [/php] Später kannst Du dann folgendes tun: [php] class NeedsLogging { ... Logging logger; ... public NeedsLogging(Logging logger) { this.logger=logger; } } Ob Du nun einen ConsoleLogger oder einen EventLogger oder whatever injezierst ist der Klasse egal. Hauptsache, das übergebene Objekt erfüllt die Schnittstelle/Fähigkeit Logging. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Fasko Geschrieben 5. November 2011 Autor Teilen Geschrieben 5. November 2011 ... Willst Du etwas modellieren, was ausdrückt, dass A b kann, also die Fähigkeit besitzt etwas zu können, dann wählst Du die Interfacevererbung. Die Implementierung entscheidet dann das Verhalten.. Hast du auch hierzu ein Beispiel? Das ist eher das Thema, das mein Buch behandelt hat. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
lilith2k3 Geschrieben 6. November 2011 Teilen Geschrieben 6. November 2011 Ich denke, Du solltest mein Beispiel nocheinmal durchlesen. In dem Beispiel ging es darum, dass ein Objekt Logging kann, also die Fähigkeit "Logging" implementiert; e.g. implementiert der Console Logger Logging: ConsoleLogger implements Logging Das ist der Inhalt des Beispiels. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Fasko Geschrieben 6. November 2011 Autor Teilen Geschrieben 6. November 2011 Ja, jetzt hat es bei mir "klick" gemacht. Wo ist der Unterschied zwischen "implements" und "extends"? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
lilith2k3 Geschrieben 6. November 2011 Teilen Geschrieben 6. November 2011 Der Unterschied ist zunächst sehr gering. Im Grunde geht es darum, verschiedene Objekte in gleichen Einsatzszenarien zu benutzen. Das Stichwort hierzu ist Polymorphismus. Polymorphismus besagt nichts anderes als, dass Du einen definierten rahmen vorgibst, den verschiedene Objekte ausfüllen können; oder anders: Polymorphismus erlaubt es Dir statt mit konkreten Objekten mit ganzen Gruppen von Objekten zu arbeiten. Nehmen wir das Beispiel der Logger. Dein Programm hat je nach Implementation zwei Ansprüche: 1) Wählst Du die klassenweise Vererbung (extends), erwartet Dein Programm ein Objekt vom Typ Logger oder alternativ ein Objekt aus der Familie (nenne ich es jetzt einmal) der Logger. 2) Wählst Du die interface Implementation erwartet Dein Programm ein beliebiges Objekt, welches die Fähigkeit Logging mit sich bringt. Soweit sehen sich die Arten der Vererbung recht ähnlich. Kommen wir zu den Unterschieden: * Mit der klassenweisen Vererbung schaffst Du die Möglichkeit eine Gruppe gleichartiger Objekte zu erschaffen - quasi: Objektfamilien. Die abgeleiteten Objekte erben von ihren Vorgängern alle Methoden die Public sind, sowie diejenigen, welche Protected sind. Du erhälst also ein Objekt, welches quasi schon Fähigkeiten mit sich bringt, ohne eine Zeile Code geschrieben zu haben. Ebenfalls werden die Attribute der Klasse, welche Public, bzw. Protected sind nach unten hin weitervererbt. Je nach Größe der Hierarchie kann das recht unübersichtlich werden. Bzw. manchmal ist es auch nicht gewünscht alle Variablen und Methoden in abgeleiteten Objekten zur Verfügung zu haben. Dann erweist sich die klassenweise Vererbung als ungünstig * Die Interfacevererbung bietet den Vorteil, dass Du Objekte verknüpfen kannst, die nichts gemein haben, außer dass sie ein gemeinsames Interface haben; also: eine gemeinsame Eigenschaft haben. Oftmals ist es genau das, was gewünscht ist: Man möchte nicht eine Reihe von verwandten Objekten behandeln, die einen gemeinsamen Stamm an Funktionen besitzen und darüber hinaus noch viele andere Funktionen besitzen, sondern oftmals hat man eine fest umrissene Anforderung, was das Objekt können soll. Diese wird fest im Interface definiert. Und alle Objekte, die genau die Fähigkeit besitzen können benutzt werden. Beispielsweise kann man eine Klasse Fortbewegungsmittel definieren, welche einen Antrieb benötigt. Der Antrieb soll die Kommandos Start und Stop beherrschen - das war's. Ob nun in das Fortbewegungsmittel ein Dieselmotor kommt, ein Raketenantrieb oder irgendeine Form des Antriebes, die wir nicht kennen, ist eigentlich egal. Hauptsache die Anforderungen werden erfüllt. * Modellierst Du Familien von Objekten kannst Du bequem neue Objekte mit neuen Funktionen hinzufügen, die die Elternobjekte noch nicht besaßen. Der Code muss nicht neu kompiliert werden. Du kannst die Objekte bequem austauschen * Bei Interfaces definierst Du eine feste Struktur - ändert sich diese Struktur, so müssen alle Klassen, die diese Struktur implementieren, neu geschrieben werden und der Code muss neu kompiliert werden. Daher eignen sich Interfacedefinitionen sehr gut für fest umrissene Schnittstellen - wie bspw. bei dem Logger-Interface. Wir haben von vornherein festgelegte Logging-Stufen, die sich voraussichtlich nicht mehr ändern werden. Also bietet es sich an, diese Struktur in einem Interface zu fixieren. Was nun die darunter fallenden Objekte bei dem Aufruf der jeweiligen Methode tun (oder lassen) bleibt ihnen überlassen. * Interfaces beinhalten keine Implementation: Die Methodenkörper müssen für die Objekte, welche die Methoden implementieren (neu) geschrieben werden. * Interfaces bieten sich an, bei fest umrissenen (abstrakten) Strukturen. Bspw. wenn ich es ermöglichen will, dass innerhalb meines Codes in irgendeiner Form Plugins ausgeführt werden sollen, bietet sich ein simples Interface Plugin an mit genau einer Methode: Execute(). Was sich dann dahinter verbirgt, soll mir als Entwickler gleich sein. So schafft man Strukturen, die einerseits fest gefügt (geschlossen) sind, da die Schnittstelle vorgefertigt ist; zum anderen, da die Details der Implementation offen gehalten werden ist unser Programm offen für Erweiterung; das nennt man auch das Open-Closed-Principle. Eines der wichtigsten Grundprinzipien der objektorientierten Programmierung. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.