2012-09-25 18 views
5

Acabo de aprender hoy un poco sobre Composición sobre herencia. Me preguntaba si debería aplicar el concepto a algo que escribí recientemente.Base abstracta o clase auxiliar

Nos previamente tenían dos clases que eran casi idénticos, aparte de un par de pequeñas diferencias. Contenían algunas características básicas de acceso a la base de datos, pero operaban en diferentes tipos de objetos (pero relacionados). Así que antes teníamos clase que se estructuraron algo como esto:

class BallMillDBHandler{ 

    public BallMillDBHandler(){ ... } 

    public void InsertTool(BallMill tool) { ... } 
    public BallMill QueryTool(string toolID) { ... } 
    public void UpdateTool(BallMill tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 

class DiamondToolDBHandler{ 

    public DiamondToolDBHandler(){ ... } 

    public void InsertTool(DiamondTool tool) { ... } 
    public DiamondTool QueryTool(string toolID) { ... } 
    public void UpdateTool(DiamondTool tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 

Tomé la mayoría de los métodos de cerca duplicado y los refactorizado a cabo en una clase BaseToolDBHandler(), y heredó de los otros dos, que proporciona unos métodos abstractos y propiedades para manejar las diferencias en el acceso a los parámetros de la base de datos.

¿Tendría sentido hacer que la BaseToolDBHandler sea una clase auxiliar en su lugar, contenida dentro de los accesadores de la base de datos, y proporcionarles una interfaz común a las propiedades/métodos previamente abstractas? ¿O debería dejarlo como un caso de herencia?

+5

Parece el lugar perfecto para la herencia, así que lo dejaría así. –

+0

Neil Kennendy tiene razón. Pero si su BaseClass solo ofrece métodos y propiedades abstractas y nunca ofrece ninguna funcionalidad implementada, use una interfaz (por ejemplo, 'IDBHandler '). –

Respuesta

3

Parece una situación que beneficiaría tanto a los genéricos como a la herencia a través de una clase/interfaz base.

class DBHandler<TTool> where TTool : ToolBase // or ITool 
{ 
    public DBHandler(){ ... } 

    public void InsertTool(TTool tool) { ... } 
    public TTool QueryTool(string toolID) { ... } 
    public void UpdateTool(TTool tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 

Si es necesario, se puede hacer una base de clase (opcionalmente abstracto), o una interfaz para su uso como una restricción de tipo que garantice ciertos miembros que se necesitan las herramientas para tener el interior de los cuerpos de los métodos.

Ejemplos:

var handler = new DBHandler<BallMill>(); 
BallMill value = handler.QueryTool("xyz"); 
value.SomeProperty = "New Value"; 
handler.UpdateTool(value); 
+1

Parece que podría ser una opción, pero dependería de lo que ocurra dentro de esos métodos; pueden o no ser lo suficientemente similares para que esto funcione. – Servy

+0

@Jamiec Indeed. Lo tengo. – Dan

+0

Creo que hacer de la base un genérico ayudaría mucho. Todavía necesito mantener un conjunto diferente de parámetros a través del cual se accede a la base de datos, y creo que mantenerlos en clases separadas es mejor que pasarlos en cada instancia. Pero esto es útil, creo que lo marcaré como la respuesta aceptada. – KChaloux

3

La herencia tiende a ser usada en exceso, pero parece ser un caso apropiado para ella. En muchos casos, las personas solo ven código duplicado y piensan "Usaré la herencia para eliminar el código duplicado a través de una clase base". En realidad, la mayoría del código duplicado se puede refactorizar en otra clase completamente utilizada en varios lugares. Usualmente las clases que lo usan no están "relacionadas", están haciendo dos cosas completamente diferentes y simplemente comparten la necesidad de hacer algunas (o algunas series de) tareas pequeñas.

La herencia se debe usar cuando las clases realmente pueden decir que la clase de clase "es" una instancia de la clase base, no solo una clase que necesita acceso a un conjunto de métodos definidos en otra parte. En su caso particular, está claro que ambas clases son controladores de bases de datos. En su punto crucial, ambos están cumpliendo el mismo objetivo general, pero son dos posibles implementaciones diferentes de ese objetivo. El único problema que pude ver aquí (dado que no has mostrado el contenido de ninguno de los métodos) es que puedes combinar ambas clases en una sola clase, pero necesitaríamos saber más sobre los detalles para saber si eso es posible o preferible.

+0

Me gustó tu definición de cuándo usar la herencia: no es solo la cursi "es una" versus "tiene una" definición, sino que realmente explicas que las clases tienen el mismo objetivo general (y por lo tanto podría ser necesario referenciarlas) de forma polimórfica, por lo que hay una buena razón para usar la herencia). Aparte de eso, no hay un beneficio real de la herencia porque la reutilización del código se puede lograr mediante la composición sin el acoplamiento y los peligros que podrían ocurrir con la herencia. – BornToCode

0

Yo diría que este es sin duda una tarea para la herencia ... pero permite aclarar una cosa en primer lugar. La composición es un patrón de diseño que puede y debe usarse cuando la herencia múltiple de clases no es una característica del lenguaje dado (C# por ejemplo)

La composición implica que su clase compuesta crea instancias de clases, donde generalmente se heredarían. En este caso, usted proporciona el contrato para la implementación a través de interfaces.

Para darle un ejemplo general de cómo la herencia puede aplicar a su código, considere esto: (esto no está utilizando la composición)

public interface IHandler 
{ 
    void InsertTool(ITool tool); 
    void UpdateTool(ITool tool); 
    void DeleteTool(string toolID); 
    //void DeleteTool(ITool tool) - seems more consistent if possible!? 

    ITool QueryTool(string toolID); 
} 

public interface ITool 
{ 

} 

class BallMill : ITool 
{ 
} 

class DiamondTool : ITool 
{ 
} 

class BallMillDBHandler : IHandler 
{ 

    public BallMillDBHandler(){ ... } 

    public void InsertTool(ITool tool) { ... } 
    public BallMill QueryTool(string toolID) { ... } 
    public void UpdateTool(ITool tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 

class DiamondToolDBHandler : IHandler 
{ 

    public DiamondToolDBHandler(){ ... } 

    public void InsertTool(ITool tool) { ... } 
    public DiamondTool QueryTool(string toolID) { ... } 
    public void UpdateTool(ITool tool) { ... } 
    public void DeleteTool(string toolID) { ... } 
} 
+0

'QueryTool' que no está en la interfaz básicamente fundamenta esta respuesta como OMI inviable. La interfaz no tiene un uso real. – Jamiec

+0

@Jamiec ... es hora de editar ... – series0ne

0

En lugar de herencia, uso de medicamentos genéricos. Desea realizar la misma operación en diferentes tipos de objetos, que es exactamente lo que hacen los genéricos.

Cuestiones relacionadas