Pregunta

Estoy tratando con una gran base de código que tiene muchas clases y muchos métodos abstractos en estas clases. Me interesan las opiniones de la gente sobre lo que debo hacer en la siguiente situación.

Si tengo una clase Parent-A con un método abstracto. Solo habrá 2 niños. Si Child-B implementa AbstractMethodA pero Child-B no lo hace, ya que no se aplica.

¿Debería

  1. ¿Eliminar la palabra clave abstracta del padre y usar virtual o dinámica?
  2. Proporcione una implementación vacía del método.
  3. Proporcione una implementación que genere un error si se llama.
  4. Ignora la advertencia.

Editar: Gracias por todas las respuestas. Confirmó mi sospecha de que esto no debería suceder. Después de una mayor investigación, resulta que los métodos no se utilizaron en absoluto, por lo que los eliminé por completo.

¿Fue útil?

Solución

Si AbstractMethodA no se aplica a Child-B, entonces Child-B no debería heredar de Parent-A.

O para tomar el contrapositivo, si Child-B hereda de Parent-A, y AbstractMethodA no se aplica al niño, entonces tampoco debería estar en el padre.

Al poner un método en Parent-A, estás diciendo que el método se aplica a Parent-A y todos sus hijos. Eso es lo que significa herencia , y si lo usa para significar algo diferente, terminará en una seria disputa con su compilador.

[Editar - dicho esto, la respuesta de Mladen Prajdic está bien si el método se aplica, pero no debe hacer nada para una o más de las clases involucradas. Un método que no hace nada es IMO, no es lo mismo que un método que no es aplicable, pero tal vez no queremos decir lo mismo con "no se aplica"]

Otra técnica es implementar el método en Child-B de todos modos, pero hacer que haga algo drástico como siempre devolver un error, o lanzar una excepción, o algo así. Funciona, pero debe considerarse como un poco más que un diseño limpio, ya que significa que las personas que llaman deben saber que lo que tienen que están tratando como Parent-A es realmente un child-B y, por lo tanto, no deberían llamar AbstractMethodA. Básicamente ha descartado el polimorfismo, que es el principal beneficio de la herencia OO. Personalmente, prefiero hacerlo de esta manera en lugar de tener una implementación de lanzamiento de excepciones en la clase base, porque entonces una clase secundaria no puede "accidentalmente". comportarse mal al "olvidar" para implementar el método en absoluto. Tiene que implementarlo, y si lo implementa para que no funcione, entonces lo hace explícitamente. Una mala situación debería ser ruidosa.

Otros consejos

Si la implementación en descendientes no es obligatoria, entonces debe ir por 1 + 2 (es decir, método virtual vacío en ancestro)

Creo que, en general, no deberías heredar de la clase abstracta si no puedes implementar todos los métodos abstractos en primer lugar, pero entiendo que hay algunas situaciones en las que todavía tiene sentido hacerlo. , (vea la clase Stream y sus implementaciones).

Creo que debería crear implementaciones de estos métodos abstractos que arrojan una excepción NotImplementedException.

También puede intentar usar ObsoleteAttribute para que llamar a ese método en particular sea un error de tiempo de compilación (además de lanzar NotImplementedException, por supuesto). Tenga en cuenta que ObsoleteAttribute no está destinado a ser utilizado para esto, pero supongo que si usa un mensaje de error significativo con comentarios, está bien.

Ejemplo de código obligatorio:

[Obsolete("This class does not implement this method", true)]
public override string MyReallyImportantMethod()
{
    throw new NotImplementedException("This class does not implement this method.");
}

hacerlo virtual vacío en la clase base y anularlo en los niños.

Podrías usar interfaces. Entonces Child-A y Child-B pueden implementar diferentes métodos y aún heredar de Parent-A. Las interfaces funcionan como métodos abstractos, ya que obligan a la clase a implementarlas.

Si algunas subclases (B1, B2, ...) de A se utilizan para un subconjunto diferente de sus métodos que otros (C1, C2, ...), se podría decir que A se puede dividir en B y C .

No conozco a Delphi demasiado bien (para nada :)), pero pensé que, por ejemplo, en Java y COM, una clase puede 'implementar' múltiples interfaces. En C ++ esto solo se puede lograr heredando múltiples clases abstractas.

Más concreto: crearía dos clases abstractas (con métodos abstractos) y cambiaría el árbol de herencia.

Si eso no es posible, una solución podría ser un "Adaptador": una clase intermedia A_nonB_ con todos los métodos B implementados vacíos (y emitiendo una advertencia al llamarlos), y A_nonC_. Luego cambie el árbol de herencia para resolver su problema: B1, B2, ... herede de A_nonC_ y C1, C2, ... herede de A_NonB_.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top