¿Cuándo mover un campo común a una clase base?

16

Actualmente tengo dos clases derivadas Ay Bambas tienen un campo en común y estoy tratando de determinar si debería subir a la clase base.

Nunca se hace referencia desde la clase base, y digamos que si en algún momento en el camino se deriva otra clase C, que no tiene un _field1, entonces no se violaría el principio de "menos privilegiado" (o algo) si ¿fue?

public abstract class Base
{
    // Should _field1 be brought up to Base?
    //protected int Field1 { get; set; }
}

public class A : Base
{
    private int _field1;
}

public class B : Base
{
    private int _field1;
}

public class C : Base
{
    // Doesn't have/reference _field1
}
Sam es
fuente
18
Creo que esta pregunta no es clara, ya que no nos ha dado ninguna idea de lo que Base, A, B, C, y _field1son. Esos son detalles importantes que no deben dejarse de lado; Creo que deberías editar la pregunta para hablar sobre cuáles son.
Tanner Swett
Según las respuestas que haría: reconstruir el vehículo para que tenga una suspensión virtual, luego el automóvil y la bicicleta podrían tener ruedas y el barco podría tener flotabilidad, lo que moverá la abstracción hacia arriba. Me parece que si mi abstracción conduce directamente a configuraciones específicas, entonces no he movido el concepto lo suficiente en la cadena.
Patrick Hughes el
66
No use la herencia de clases para evitar duplicar el código. Úselo para heredar y extender el comportamiento , es decir, el polimorfismo. Mueva un campo común a una clase base si y solo si es lógicamente el mismo campo, no dos piezas de información no relacionadas que comparten el mismo nombre en sus respectivos contextos.
Brandon
¿Por qué tienes una clase base para empezar?
jpmc26

Respuestas:

34

Todo depende del problema exacto que intente resolver.

Considere un ejemplo concreto: su clase base abstracta es Vehicley actualmente tiene implementaciones concretas Bicycley Car. Estás considerando mudarte numberOfWheelsdesde Bicycley Carhacia el vehículo. ¿Deberías hacer esto? ¡No! Porque no todos los vehículos tienen ruedas. Ya puede decir que si intenta agregar una Boatclase, entonces se romperá.

Ahora, si su clase base abstracta era WheeledVehicleentonces es lógico tener la numberOfWheelsvariable miembro allí.

Debe aplicar la misma lógica a su problema, porque como puede ver, no es una respuesta simple de sí o no.

Pete
fuente
3
Uno podría aceptar temporalmente que 0 es un número válido de ruedas. Sin embargo, eventualmente podría agregar un roll()método, momento en el cual la idea de la subclase parece premonitoria.
user949300 el
11
Un bote tiene 0 ruedas. ¿Qué rompe eso?
D Drmmr
14
@DDrmmr No es que un Barco tenga 0 ruedas, sino que las Ruedas ni siquiera existen como concepto para un Barco, por lo tanto, sus modelos no deberían permitirlo.
Peter M
10
Mi punto es que el ejemplo es malo. No hay nada conceptualmente incorrecto con un vehículo (que resulta ser un barco) que indique que tiene 0 ruedas.
D Drmmr
10
Entonces todo se va al infierno cuando necesitas guardar un bote de remos.
IllusiveBrian
13

Hablando lógicamente, más allá de colocar el campo replicado en subclases versus en común en la clase base, hay una tercera opción: que es introducir una nueva subclase en la jerarquía que tiene las propiedades comunes entre los dos. @Pete insinúa esto sin ir completamente allí.

Usando el ejemplo de @Pete, introduciríamos una subclase (posiblemente abstracta) para Vehículo con ruedas que desciende de la clase base original, mientras que las dos subclases descienden de ella. Por lo tanto, la clase base original no está contaminada con ruedas, pero la característica común de las ruedas es SECA (no se repite entre las subclases que tienen ruedas).

Esto puede, por supuesto, ser excesivo para sus propósitos, pero el mecanismo de jerarquía de clases lo admite.

Erik Eidt
fuente
Esto es en realidad lo que he decidido hacer (A y B se superponen principalmente, por lo que B derivará de A).
samis
9

Voy a jugar al abogado del diablo aquí.

En este momento no deberías hacer nada .

¿Está SECO? No. Pero es mejor tener un poco de duplicación que una abstracción prematura de la que no pueda retroceder fácilmente más adelante. El refactor para mover una propiedad a una clase base común es fácil. Ir por el otro lado no lo es. Espera y verás.

Cuando tomo este tipo de decisión, tiendo a usar una "regla de 3": una vez que he repetido lo mismo, por ejemplo, en tres lugares diferentes, y solo entonces, considero subirlo por la cadena. Nota: solo tienes 2 años.

Jared Smith
fuente
2
Una sabia observación que es, diría, necesaria para tomar la decisión.
radarbob
1
Estoy de acuerdo en su mayoría, pero "en este momento" (sin un código adicional como el que vemos) la refactorización en ambas direcciones es trivial. Pero si hay un código adicional que utiliza el campo, la refactorización en ambas direcciones puede ser significativamente más difícil.
Doc Brown
2

En general, lo movería a la clase base. No creo que haya un objetivo sí / no, porque hay una compensación aquí: llevar campos no utilizados frente a reducir la complejidad.

Por lo general, prefiero las clases base 'pesadas' que contienen cualquier cosa que pueda compartirse. Esto simplifica la serialización de archivos ya que no necesita métodos de serialización descendientes en cada clase derivada. Pero si no tiene ese problema o un problema similar, o tal vez necesita hacer todo lo posible para reducir el uso de memoria, entonces solo mantener los campos donde los necesita debería estar bien.

Una clase 'intermedia' que introduce los campos comunes estará bien si tiene un número muy limitado de campos. Pero tenga en cuenta que el enfoque puede aumentar drásticamente la complejidad si tiene docenas de campos utilizados en diferentes combinaciones, lo que lleva a muchas clases intermedias, cada una de las cuales introduce un conjunto específico de campos. Eso puede convertirse en un problema de mantenimiento.

Gran maestro B
fuente
Mi ejemplo es trivial, aunque todavía es un código de producción. Usted hace un buen argumento para "comprometer" la jerarquía con una clase base "pesada", a la que yo también me inclinaría en tal caso.
samis
1
@samis: ¿usas clases llamadas "A, B, C" y "Base" con un solo campo y ningún método en el código de producción? Yo cuestiono eso.
Doc Brown el