2008-10-20 7 views
15

Me he enfrentado a este problema con bastante frecuencia durante los últimos meses, durante los cuales he estado construyendo este sistema. El escenario es el siguiente: tengo este tipo de objeto que esencialmente es una lista de otros objetos, pero tiene otras propiedades específicas de su naturaleza. Por ejemplo:¿Debería subclase la Lista <T> o tenerlo como una propiedad?

  • Clase Tests:
    • Contiene muchos objetos Test
    • tiene propiedades:
      • DefaultTimeouts
      • DefaultNumberOfTries

puedo tener este subclase clase List<Test> o debería tenerlo heredando de Object, simplemente tener la lista como una propiedad al lado de los otros campos?

Sé que esto puede ser un poco subjetivo y el gusto personal podría desempeñar un papel aquí, pero de corazón me gustaría saber su opinión al respecto.

+0

Hay muchos comentarios, sin embargo, nadie sabe en qué idioma está escribiendo. Hay bastantes que usan la sintaxis del paréntesis angular para los parámetros de tipo, pero con detalles bastante diferentes sobre lo que hacen, y diferentes reglas de lo que puede cuenta y cuáles son los modismos normales. –

Respuesta

12

Contrariamente a la mayoría de las respuestas aquí, no me subclases de la lista en la mayoría de los casos. Descubrí que heredar de una clase para reutilizar la funcionalidad generalmente causa problemas más adelante.

Normalmente solo tengo una propiedad del tipo List (o IList) que devuelve una referencia a la lista. Por lo general, solo necesita obtener una propiedad aquí. Puede controlar el acceso a la lista eligiendo devolver una versión de solo lectura de la lista con .AsReadOnly() o simplemente exponiendo la lista como un IEnumerable.

En los casos en que deseo que las pruebas sean una lista Normalmente implemento IList y llamo a un campo de lista interno para las implementaciones reales de IList. Esto es un poco más laborioso y da como resultado más código para mantener, pero he descubierto que es mejor mantenerlo que heredar la Lista solo por su implementación.

+0

Me parece genial, y concuerda con mis propias conclusiones de la discusión. ¡Gracias! –

+0

Una cosa: en los casos en que devuelve .AsReadOnly, ¿regresa normalmente como ReadOnlyCollection? –

+1

Volvería como IList, ya que el hecho de que sea ReadOnlyCollection generalmente no es importante para el usuario final de la clase. – Guvante

1

Si literalmente hace todo un List haría, y todas las funciones List actuaría sobre el objeto Tests de una manera intuitiva que da el resultado correcto, a continuación, en mi opinión, debería simplemente subclase List<Test>.

De lo contrario, tendrá una clase con un montón de métodos que solo llaman a un método del mismo nombre en la variable List<Test> en la instancia. Eso solo será una extensión imperfecta de la clase List<Test>.

1

La herencia generalmente se asigna a una relación "is-a". Dado que su contenedor es una lista, pero con algunas otras cosas, heredaría de List y agregaría sus propiedades adicionales a su subclase.

0

En su ejemplo, dijo "Las pruebas de clase contienen muchos objetos de prueba", no "Las pruebas de clase son una colección de objetos de prueba". IMO no es necesario subclasificar la Lista en este escenario a menos que necesite tener una interfaz tipo Lista para esta clase.

Sin embargo, la respuesta realmente depende del contexto de la clase de pruebas. Si se comporta como List y se usará en contextos donde se espera Lista de objetos, herede de List.

Tenga en cuenta que la herencia es más difícil de mantener que la composición.

Además, me gustaría cambiar el nombre de pruebas para TestCollection (si subclase de lista), o algo así TestUnit (si contendría lista de clases de prueba.

+0

Buen consejo sobre el cambio de nombre, aku. Tomaré eso en consideración. Tengo este horrible hábito de nombrar algunas clases, prefiero llamar sus * instancias *, ¡no las clases en sí mismas! –

6

sub-clase de la Lista < T>. Si usted tiene la lista genérica como una propiedad, no es así encapsulado como una subclase.

Si se ve como una lista < T> y suena como una lista < T>, probablemente no es una lista < T>

Lo llamaría TestCollection.

0

"Favorecer la composición sobre la herencia" es siempre una buena regla empírica. ¿Los métodos que usan esta clase usan todos los métodos de la Lista, así como los que agrega o solo los que agrega?

+0

¿Por qué sería una buena regla general, Camas? Parece que ese concepto es la clave aquí, ¿verdad? –

1

No creo que lo que tienes es una simple "lista de pruebas", porque necesitabas algo más. Sugeriría que lo llames TestSuite y que la Lista sea una propiedad. Has-a es mucho más fácil de mantener en comparación con la herencia.

En general, tendría mucho cuidado de heredar algo así como List.

+0

¿Por qué tendrías cuidado con eso? –

+0

1) Debido a que no posee ni comprende el origen de la Lista, y la herencia introduce un acoplamiento cerrado entre el padre y la subclase. 2) El código de la biblioteca puede cambiar con el tiempo. 3) El consumidor de su Clase tiene expectativas ya que la Lista es ampliamente utilizada. –

+0

Gracias por la aclaración. Sin embargo, ¿implica 1 que uno debe evitar heredar del BCL? Además, no pude entender 3 como un inconveniente. –

1

Al leer las respuestas, parece que la pregunta clave es ¿a qué longitud es su objeto realmente una lista? Así que tal vez un buen compromiso entre los peligros de la herencia y la falta de transparencia de la composición sería tener un List<Test> como un backend privado y exponer solo los métodos que se utilizarían.

Cuestiones relacionadas