Sie haben bereits ein paar nette Antworten erhalten, aber der riesige Elefant im Raum in Ihrer Frage ist dieser:
von jemandem gehört, dass die Verwendung von Vererbung vermieden werden muss und wir stattdessen Schnittstellen verwenden sollten
Als Faustregel gilt: Wenn Ihnen jemand eine Faustregel gibt, ignorieren Sie diese. Dies gilt nicht nur für "jemand, der Ihnen etwas erzählt", sondern auch für das Lesen von Inhalten im Internet. Solcher Rat ist wertlos und oft sehr schädlich, es sei denn, Sie wissen warum (und können wirklich dahinter stehen).
Nach meiner Erfahrung sind die wichtigsten und hilfreichsten Konzepte in OOP "niedrige Kopplung" und "hohe Kohäsion" (Klassen / Objekte wissen so wenig wie möglich voneinander und jede Einheit ist für so wenig wie möglich verantwortlich).
Geringe Kopplung
Dies bedeutet, dass jedes "Bündel von Dingen" in Ihrem Code so wenig wie möglich von der Umgebung abhängen sollte. Dies gilt für Klassen (Klassenentwurf), aber auch für Objekte (tatsächliche Implementierung), "Dateien" im Allgemeinen (dh Anzahl #include
s pro einzelne .cpp
Datei, Anzahl import
pro einzelne .java
Datei usw.).
Ein Zeichen dafür, dass zwei Entitäten gekoppelt sind, ist, dass eine von ihnen unterbrochen wird (oder geändert werden muss), wenn die andere in irgendeiner Weise geändert wird.
Vererbung erhöht offensichtlich die Kopplung; Durch Ändern der Basisklasse werden alle Unterklassen geändert.
Schnittstellen reduzieren die Kopplung: Indem Sie einen klaren, methodenbasierten Vertrag definieren, können Sie alles an beiden Seiten der Schnittstelle frei ändern, solange Sie den Vertrag nicht ändern. (Beachten Sie, dass "interface" ein allgemeines Konzept ist. Die interface
abstrakten Java- oder C ++ - Klassen sind lediglich Implementierungsdetails.)
Hoher Zusammenhalt
Dies bedeutet, dass jede Klasse, jedes Objekt, jede Datei usw. so wenig wie möglich betroffen oder dafür verantwortlich ist. Das heißt, vermeiden Sie große Klassen, die viel zu tun haben. Wenn Ihre Waffen in Ihrem Beispiel völlig unterschiedliche Aspekte haben (Munition, Schussverhalten, grafische Darstellung, Inventardarstellung usw.), können Sie verschiedene Klassen haben, die genau eines dieser Dinge darstellen. Die Hauptwaffenklasse verwandelt sich dann in einen "Inhaber" dieser Details; Ein Waffenobjekt ist dann kaum mehr als ein paar Zeiger auf diese Details.
In diesem Beispiel würden Sie sicherstellen, dass Ihre Klasse, die das "Feuerverhalten" darstellt, so wenig wie möglich über die Hauptwaffenklasse weiß. Optimalerweise gar nichts. Dies würde zum Beispiel bedeuten, dass Sie jedem Objekt in Ihrer Welt (Türmen, Vulkanen, NSCs ...) mit einem Fingerschnipp "Feuerverhalten" verleihen könnten . Wenn Sie irgendwann ändern möchten, wie Waffen im Inventar dargestellt werden, können Sie dies einfach tun - nur Ihre Inventarklasse weiß darüber Bescheid.
Ein Zeichen dafür, dass eine Entität nicht zusammenhängend ist, ist, dass sie immer größer wird und sich gleichzeitig in mehrere Richtungen verzweigt.
Erbschaft, wie Sie sie beschreiben, verringert den Zusammenhalt - Ihre Waffenklassen sind letztendlich große Brocken, die alle möglichen unterschiedlichen, nicht verwandten Aspekte Ihrer Waffen behandeln.
Schnittstellen erhöhen indirekt den Zusammenhalt, indem sie Verantwortlichkeiten zwischen den beiden Seiten der Schnittstelle klar aufteilen.
Was nun
Es gibt immer noch keine festen Regeln, all dies sind nur Richtlinien. Im Allgemeinen wird, wie der Benutzer TKK in seiner Antwort erwähnte, die Vererbung viel in der Schule und in Büchern unterrichtet. es ist das schicke Zeug über OOP. Das Lehren von Interfaces ist wahrscheinlich langweiliger und erschließt (wenn Sie an trivialen Beispielen vorbeigehen) das Feld der Abhängigkeitsinjektion, das nicht so eindeutig ist wie die Vererbung.
Letztendlich ist Ihr vererbungsbasiertes Schema immer noch besser, als überhaupt kein klares OOP-Design zu haben. Fühlen Sie sich also frei, dabei zu bleiben. Wenn Sie möchten, können Sie ein wenig über niedrige Kopplung, hohe Kohäsion nachdenken und nachsehen, ob Sie Ihrem Arsenal diese Art des Denkens hinzufügen möchten. Sie können jederzeit nacharbeiten, um dies zu einem späteren Zeitpunkt auszuprobieren. Oder probieren Sie schnittstellenbasierte Ansätze in Ihrem nächsten größeren neuen Codemodul aus.