2010-06-17 4 views
6

Tengo clases de comandos que implementan la interfaz ICommand {Execute}. Varios comandos tienen piezas duplicadas de código. Tengo varias opciones de cómo secar:Clase (s) de ayuda frente a la herencia funcional. Mejor práctica

  • Crear clase auxiliar estática (es) y mover el código duplicado existe
  • crear comandos herencia con métodos auxiliares protegidas

¿Qué sugeriría usted y por qué?

AÑADIDO Gracias a todos los que respondieron, ¡muchas respuestas fueron parecidas y útiles!

Respuesta

3

Depende completamente de la naturaleza de su código duplicado.

¿Cuáles son las entradas/salidas de sus funciones auxiliares? ¿Funcionan en un conjunto de variables relacionadas lógicamente? Entonces, sí, será mejor que cree una clase base con esas variables como miembros y un conjunto relacionado de funciones auxiliares.

De lo contrario, si los parámetros en sus funciones auxiliares no son coherentes, implementaría esas funciones como funciones estáticas de todos modos, ¿verdad? No veo razones para complicar las cosas con herencia en este caso y lo haría solo con funciones auxiliares (o, si su lenguaje no trata las funciones como ciudadanos de primera clase, use clases de ayuda estática).

3

Si existe la posibilidad de que la lógica duplicada también sea necesaria para otras clases fuera de la jerarquía, la incluiría en clases estáticas de ayuda. De lo contrario, en la clase base con herencia protegida.

2

En mi opinión, colocaría el código duplicado en la clase base si solo se relaciona con esa jerarquía de clases y no se usará fuera de ella. Si existe alguna posibilidad de que el código se use en diferentes clases, muévalo a una clase auxiliar dentro de un proyecto común.

¡Disfrútalo!

5

En lugar de clases estáticas, otra opción es poner el código común en una nueva clase y usar la inyección de dependencia para inyectar la clase auxiliar en los comandos. Esto también va con la composición sobre la noción de herencia también.

+0

O al revés: haga que la clase auxiliar sea decoradora e inserte la clase de comando en la clase auxiliar. – Ozan

+2

+1 Al pensar en la reutilización de código, no piense en "herencia", piense en "agregación". –

1

Probablemente no haya una respuesta correcta/incorrecta aquí, aunque supongo que ciertamente podría implementarla mal. Es muy probable que dependa de sus requisitos reales y de cuán relacionados estén sus comandos entre sí. En general, probablemente iría con una jerarquía de implementación y herencia de clase base, suponiendo que los comandos están relacionados y el código se relaciona directamente con los comandos mismos, no con una entidad externa que debería ser una clase en sí misma. Ciertamente están relacionados por el hecho de que son comandos y la clase base podría reflejar eso.

Sin embargo, si tiene un código que es común a subconjuntos de comandos no relacionados, y la creación de una jerarquía de herencia forzará una relación que no existe, y luego agregará una clase "auxiliar" (no estática, si posible, para mejorar la capacidad de prueba) sería una forma perfectamente natural de abordar el problema. Puede encontrar que puede agrupar los métodos de "ayuda" naturalmente en clases propias. Por ejemplo, si varios métodos necesitan interactuar con su subsistema de autenticación, es posible que tenga un AuthenticationMediator para esos métodos. Tampoco veo ningún conflicto con hacer algunos de ambos.

0

Si la lógica funciona en la interfaz miembros, en oposición a la ejecución miembros, a continuación, escribir un método de ayuda [o método de extensión] se aconseja.

public IRandom 
{ 
    byte NextByte(); 
} 

public static class IRandomExtensions 
{ 
    // logic that acts against public interface IRandom 
    // may be applied to all implementations 
    public static int GetNextUnbiasedInteger (this IRandom random) { } 
    public static IEnumerable<T> Shuffle<T> (
     this IRandom random, 
     IEnumerable<T> items) { } 
} 

Si la lógica de negocio opera en contra de implementación miembros,

public class SomeCommand : ICommand 
{ 
    // an implementation-specific member, NOT a member 
    // of ICommand 
    public int SomeControlCount { get; set; } 
} 

// a method that references implementation-speciic 
// details. where should this go? 
public void DoSomething() 
{ 
    SomeCommand command; 
    int count = command.SomeControlCount; 
} 

entonces es probable que debe unirse más estrechamente esto a la clase de implementación. Si esto es una ocurrencia común, entonces una clase base puede tener sentido.

Personalmente, las jerarquías complejas son más problemáticas que lo que valen, use su propio juicio con respecto a la facilidad de mantenimiento, la legibilidad y la reutilización, ¡y debería estar bien!

Espero que esto ayude! :)

0

Code sin estado use helpers.

El código dependiente del estado con varios métodos usa la herencia. Por ejemplo, cuando varios métodos usan una variable de miembro compartida y, por lo tanto, mantienen un estado compartido.

El objetivo es reducir la cantidad de código duplicado y depende de qué tipo de código sea. Sin embargo, realmente odio cuando la gente exagera y hace clases súper abstractas o funciones auxiliares que hacen 7 saltos a otro código abstracto estrangulado, que se denominan algo así como "Ejecutor" "Invoker" "DataConveyer" "DataManager" "Código Compartido". Y que, de alguna manera, al final de todos estos saltos realmente logró hacer el trabajo que se suponía, pero está tan interconectado entre sí que no está seguro de dónde hacer los nuevos cambios para agregar esta nueva característica. ¿Debo hacerlo DataConveyer o debería hacerlo en DataManager?

Por lo que el objetivo de oro debería ser, mantenerlo simple.

1

El uso de ayudantes dentro de su propio código es una mala práctica que proviene de la pereza.

El único posible situación que realmente necesita ayudantes - es extender el comportamiento de las clases cerradas de las bibliotecas 3 ª parte como el selenio, etc.

¿Cuál es ayudante? Es un método estático que se encuentra en algún lugar de la clase en sí.

¿Qué problemas obtenemos?

  1. método estático. Tiene problemas con las pruebas de la unidad. Por ejemplo, nuestros desarrolladores agregaron el almacenamiento en caché a los ayudantes. Como resultado, no había ninguna posibilidad de simplemente burlarse de estos métodos, mientras que yo tenía que agregar a mucha lógica solo por simple burla. Sí, hay una posibilidad de uso incorrecto del método estático ... pero al principio nadie esperaba agregar estado al helper.
  2. ubicación. El método se encuentra en otra clase, lejos de la lógica básica. Es una concepción errónea del diseño del código.

¿Cuándo usar el ayudante? Cuando necesite expandir una biblioteca de terceros sin posibilidad de heredarla. De lo contrario, simplemente herede lib.

¿Cuándo no utilizar ayudantes? Para reducir el código duplicado. Necesita mover este código a otro servicio.Lea acerca de DDD para mejorar las habilidades de refactorización y sepa cómo personalizar el servicio de la mejor manera

Cuestiones relacionadas