2009-03-08 8 views
6

Antes de la introducción a los genéricos al lenguaje Java, habría escrito clases encapsulando colecciones-de-colecciones-de-colecciones. Por ejemplo:Para usar colecciones genéricas anidadas o clases intermedias personalizadas?

class Account { 
    private Map tradesByRegion; //KEY=Region, VALUE=TradeCollection 
} 

class TradeCollection { 
    private Map tradesByInstrument; //KEY=Instrument, Value=Trade 
} 

Por supuesto, con los genéricos, que sólo puede hacer:

class Account { 
    private Map<Region, Map<Instrument, Trade>> trades; 
} 

tiendo a optar ahora por la opción # 2 (sobre una versión generified de la opción # 1) porque esto significa que no termino con una proliferación de clases que existen únicamente con el propósito de envolver una colección. Pero tengo la molesta sensación de que este es un mal diseño (por ejemplo, cuántas colecciones anidadas debo usar antes de declarar nuevas clases). Opiniones?

Respuesta

4

2 es mejor porque:

  • código Menos logra el mismo efecto (mejor, en realidad, como en # 1 parte de su información de tipo existe sólo en los comentarios)
  • Es del todo claro qué es yendo en adelante.
  • Sus errores de tipo serán capturados en tiempo de compilación.

¿Qué hay para recomendar 1? Ciertamente, el mapa < Entero, < Mapa < Cadena, < Mapa < ... los genéricos son un poco difíciles de acostumbrar, pero en mi opinión es mucho más fácil de entender que el código con mapas, listas de mapas y mapas de listas de mapas y objetos personalizados llenos de listas de mapas.

+0

He editado la pregunta para hacer claro que una opción post-generics # 1 aún sería segura, como lo haría con los mapas –

1

Prefiero # 2. Está más claro lo que está pasando, y es seguro en tiempo de compilación (prefiero tener tantas cosas que salen mal en el momento de la compilación como sea posible, en lugar de tenerlas en tiempo de ejecución ... en general me gusta cuando no sale nada) .

Editar:

Bueno, hay dos maneras en que puedo ver ... supongo que depende de lo que se debería utilizar:

class Account 
{ 
    private Map<Region, TradeCollection> tradesByRegion; 
} 

class TradeCollection 
{ 
    private Map<Instrument, Trade> tradesByInstrument; 
} 

o

class Account<R extends Region, I extends Instrument, T extends Trade, C extends TradeCollection<I, T>> 
{ 
    private Map<R, C> tradesByRegion; 
} 

class TradeCollection<I extends Instrument, T extends Trade> 
{ 
    private Map<I, T> tradesByInstrument; 
} 
+0

Por supuesto; pero podría hacer # 1 tipo seguro al incluir genéricos. Editaré mi pregunta –

+0

Comencé a decir eso. pero a medida que lo hice genérico terminé con esencialmente el mismo código ... Lo intentaré de nuevo y veré qué obtengo – TofuBeer

2

he hecho esta regla simple para mí: Nunca más de dos < y dos comas en una declaración de genéricos y preferiblemente solo una coma. Después de eso introduzco tipos personalizados. Creo que este es el punto donde la legibilidad es suficiente para garantizar conceptos adicionales.

Existe una buena razón para evitar los genéricos demasiado profundos: la complejidad no está solo en la declaración real, sino que generalmente tiende a ser igualmente visible en la lógica de construcción. De modo que una gran cantidad de código tiende a complicarse si anida estas declaraciones demasiado profundamente. Crear clases intermedias puede ayudar mucho. El truco suele ser encontrar las clases intermedias adecuadas.

Definitivamente creo que deberías retroceder un poco hacia tu viejo estándar. En realidad, tu segunda muestra es el punto exacto en el que aún aceptaría medicamentos genéricos.

+0

No mostraré mis genéricos entonces (tengo uno que cubre aproximadamente 10 líneas para mantenerlo legible) :-) – TofuBeer

+0

@TofuBeer Mejor no hacer eso. Es un código de solo escritura en mi mundo :) – krosenvold

+0

Por supuesto, un problema con el n. ° 1 es que terminas haciéndote muchas preguntas como "¿qué era una colección de negocios otra vez?" - Es decir, necesitas hacer mucha más navegación de código desde la clase de Cuenta para entender cuál es la estructura de la colección de comercio en realidad es –

2

Normalmente también habrá algún código para operar en las colecciones. Cuando esto no es trivial, empaqueté la colección con el comportamiento en una nueva clase. Cuanto más profundo es el anidamiento, más probable es que este sea el caso.

4

Combinación de los dos. Si bien puede usar genéricos para reemplazar clases personalizadas, aún querrá usar una clase para encapsular sus conceptos. Si solo está pasando mapas de mapas de mapas de listas a todo, ¿quién controla lo que puede agregar? ¿Quién controla lo que puedes eliminar?

Para almacenar los datos, los genéricos son una gran cosa. Pero todavía quiere métodos para validar cuando agrega una operación, o agrega una cuenta, y sin algún tipo de clase que envuelva sus colecciones, nadie lo controla.

+0

Estoy de acuerdo: creo que las colecciones son un detalle de implementación y no las paso ni las expongo en la API pública –

2

Creo que es mejor tener en cuenta los objetos y enfatizar las colecciones un poco menos. Reification es tu amigo

Por ejemplo, es natural tener objetos de Estudiante y Curso si está modelando un sistema para una escuela. ¿Dónde se deben capturar las calificaciones? Yo diría que pertenecen a un objeto en el que el Estudiante y el Curso se encuentran: una ReportCard. No tendría una GradeCollection. Dale un comportamiento real.

+0

I de acuerdo: ReportCard vs GradeCollection es un muy buen ejemplo de buena elección de diseño en mi libro. – javashlook

1

Creo que la respuesta a esto es que depende de la situación. Generalmente, la introducción de un tipo es útil si eso también introduce métodos relacionados con el tipo, si esos tipos intermedios se pasan de forma independiente, etc.

Puede encontrar este consejo de Rich Hickey (el creador de Clojure) sobre la creación bibliotecas interoperables algo interesante:

está pensado como asesoramiento específico a los escritores de la biblioteca de Clojure pero creo que es interesante comida para el pensamiento, incluso en Java.

Cuestiones relacionadas