Ya tienes algunas buenas respuestas, pero el gran elefante en la habitación en tu pregunta es esta:
alguien ha escuchado que se debe evitar el uso de la herencia, y deberíamos usar interfaces en su lugar
Como regla general, cuando alguien te da una regla general, ignórala. Esto no solo va para "alguien que te dice algo", sino también para leer cosas en Internet. A menos que sepa por qué (y realmente puede respaldarlo), dicho consejo no tiene valor y, a menudo, es muy dañino.
En mi experiencia, los conceptos más importantes y útiles en OOP son "bajo acoplamiento" y "alta cohesión" (las clases / objetos saben lo menos posible el uno del otro, y cada unidad es responsable de la menor cantidad de cosas posible).
Acoplamiento bajo
Esto significa que cualquier "paquete de cosas" en su código debe depender de su entorno lo menos posible. Esto se aplica a las clases (diseño de clase) pero también a los objetos (implementación real), "archivos" en general (es decir, número de #include
s por .cpp
archivo único , número de import
por .java
archivo individual , etc.).
Una señal de que dos entidades están acopladas es que una de ellas se romperá (o necesita ser cambiada) cuando la otra se cambie de alguna manera.
La herencia aumenta el acoplamiento, obviamente; El cambio de la clase base cambia todas las subclases.
Las interfaces reducen el acoplamiento: al definir un contrato claro basado en métodos, puede cambiar cualquier cosa sobre ambos lados de la interfaz libremente, siempre que no cambie el contrato. (Tenga en cuenta que "interfaz" es un concepto general, las interface
clases abstractas Java o C ++ son solo detalles de implementación).
Alta cohesión
Esto significa que cada clase, objeto, archivo, etc. se preocupe o sea responsable de la menor cantidad posible. Es decir, evite las clases grandes que hacen muchas cosas. En su ejemplo, si sus armas tienen aspectos completamente separados (munición, comportamiento de disparo, representación gráfica, representación de inventario, etc.), entonces puede tener diferentes clases que representan exactamente una de esas cosas. La clase de arma principal se transforma en un "titular" de esos detalles; un objeto de arma es poco más que unos pocos indicadores de esos detalles.
En este ejemplo, se aseguraría de que su clase que representa el "Comportamiento de disparo" sepa lo menos humanamente posible sobre la clase de arma principal. Óptimamente, nada en absoluto. Esto significaría, por ejemplo, que podría dar "Comportamiento de disparo" a cualquier objeto en su mundo (torretas, volcanes, PNJ ...) con solo un chasquido de un dedo. Si en algún momento desea cambiar la forma en que se representan las armas en el inventario, simplemente puede hacerlo, solo su clase de inventario lo sabe.
Una señal de que una entidad no es coherente es si crece más y más, ramificándose en varias direcciones al mismo tiempo.
La herencia tal como la describe disminuye la cohesión: sus clases de armas son, al final del día, grandes pedazos que manejan todo tipo de aspectos diferentes y no relacionados de sus armas.
Las interfaces aumentan indirectamente la cohesión al dividir claramente las responsabilidades entre los dos lados de la interfaz.
Qué hacer ahora
Todavía no hay reglas duras y rápidas, todo esto son solo pautas. En general, como el usuario TKK mencionó en su respuesta, la herencia se enseña mucho en la escuela y los libros; son las cosas elegantes sobre OOP. Las interfaces son probablemente más aburridas de enseñar, y también (si pasa ejemplos triviales) un poco más difícil, abriendo el campo de la inyección de dependencia, que no es tan claro como la herencia.
Al final del día, su esquema basado en la herencia es aún mejor que no tener un diseño claro de OOP. Así que siéntase libre de seguir con eso. Si lo desea, puede reflexionar / googlear un poco sobre Acoplamiento bajo, Cohesión alta y ver si desea agregar ese tipo de pensamiento a su arsenal. Siempre puede refactorizar para probar eso si lo desea, más tarde; o pruebe los enfoques basados en la interfaz en su próximo nuevo módulo de código más grande.