2009-08-07 8 views
9

Tengo un tipo genérico relativamente complicado (digamos Map<Long,Map<Integer,String>>) que uso internamente en una clase. (No hay visibilidad externa, es solo un detalle de implementación). Me gustaría ocultar esto en un typedef, pero Java no tiene esa facilidad.¿Hay alguna vez justificación para el "antipattern pseudo-typedef"?

Ayer redescubrí el siguiente modismo y me decepcionó saber que es considered an anti-pattern.


class MyClass 
{ 
    /* "Pseudo typedef" */ 
    private static class FooBarMap extends HashMap<Long,Map<Integer,String>> { }; 

    FooBarMap[] maps; 

    public FooBarMap getMapForType(int type) 
    { 
    // Actual code might be more complicated than this 
    return maps[type]; 
    } 

    public String getDescription(int type, long fooId, int barId) 
    { 
    FooBarMap map = getMapForType(type); 
    return map.get(fooId).get(barId); 
    } 

    /* rest of code */ 

} 

¿Puede haber alguna justificación alguna para este tipo cuando está oculto y no está formando parte de una API de biblioteca (que en mi lectura son la excepción principal de Goetz a usarlo)?

+6

¿Llamas a ese tipo genérico complicado? ¡Decir ah! Cuando era pequeño teníamos que levantarnos a las 3 de la mañana con genéricos anidados recursivamente de seis niveles ... –

+1

Sí ... sin zapatos ... cuesta arriba ... en la nieve ... – skaffman

+2

@Marcus Downing : Y el séptimo nivel que desayuna en el restaurante al final de la recursión. ;-) – Mnementh

Respuesta

5

El verdadero problema es que este lenguaje crea un acoplamiento de alta entre su seudo typedef y su código de cliente. Sin embargo, ya que está usando FooBarMap en privado, no hay problemas reales de acoplamiento (son detalles de implementación).

NB

Un moderno IDE Java debe definitivamente ayuda a hacer frente a los tipos genéricos complicados.

+0

Si no usa esta expresión idiomática, está creando un alto acoplamiento entre la larga y complicada descripción de tipo ('HashMap >') y el código del cliente. ¿Podría explicar por qué el acoplamiento del antipattern es peor que eso? – bacar

+1

@bacar El problema es si alguien puede usar un 'HashMap >' o su 'FooMap'. Para usar una API que tenga un 'FooMap', no se puede pasar un HashMap. Es decir, solo son polimórficos en una dirección si se declaran en un método de interfaz. – Bringer128

2

Para interfaces públicas No me gusta ver tipos genéricos, porque no tienen ningún significado. Para mí, ver un método con un argumento de HashMap < Long, Map < Integer, String >> es muy parecido a los métodos C como foo (int, int, int, void *, int) y así sucesivamente. Tener un tipo real simplemente hace que el código sea mucho más fácil de leer. Para una interfaz pública sería mejor crear FooBarMap que envuelve HashMap < Long, Map < Entero, String >> en lugar de 'typedef', pero para el uso interno de la clase no veo ninguna desventaja en absoluto.

+0

El problema con este enfoque es que el código del cliente pierde la utilidad de la estructura de datos del Mapa. – skaffman

+2

No, todavía está allí ... – marijne

0

Sin esta pseudo-typedef yo preferiría escribir

private Map<Long,Map<Integer,String>>[] maps; 

y si algún día decido hacer cambiar la clase de implementación de HashMap a TreeMap o Java7GreatEnhancedWonderfulMap :-) nada va a romper. Pero con esto, estás atascado con el HashMap. Bueno, puede hacer:

interface FooBarMap extends Map<Long,Map<Integer,String>> { }; 
class FooBarHashMap extends HashMap<Long,Map<Integer,String>> implements FooBarMap{ }; 

pero se vuelve cada vez más engorroso.

+2

No es cierto porque el tipo en el ejemplo es privado, de hecho, la ruta 'typedef' guarda algunos tipeos porque solo tiene que reemplazar Map -> HashMap en un lugar del código. – marijne

+0

Si declaro un campo con el tipo Map, el compilador no me deja llamar a los métodos que no están declarados en la interfaz. Y si sustituyo la clase implementadora con otra clase que implementa Map, todo el código seguirá funcionando. Si lo declaro como un HashMap, puedo llamar a los métodos de HashMap. Y sustituyendo el tipo en "typedef" romperá el código. Si algún día quiero cargar mi mapa desde DB usando Hibernate, puedo hacerlo. Si tengo HashMap, tengo que crear nuevo y copiar el contenido de Map proporcionado por Hibernate. Generalmente, se recomienda encarecidamente el uso de interfaces donde sea posible. Este idioma lo desalienta. –

0

Él tiene un buen punto acerca de esto cuando se trata de ponerlo en una interfaz pública. Esta expresión idiomática está emulando alguna forma de azúcar sintáctica, no debería afectar lo que le muestras a tus clientes.

Pero no veo una buena razón para no usarlo localmente, siempre que le haga la vida más fácil y el código sea más legible, y usted sabe lo que está haciendo. Brian puede generalizar y desaconsejarlo en cualquier situación, pero esa es su sensación de Goetz: p

0

Si solo lo usa en una pequeña unidad de código localizada, los problemas son pequeños, verdaderos.

La cosa es así, también lo son las ganancias: su programa probablemente ni siquiera se reducirá textualmente hasta que haga referencia al pseudo-typedef 5+ veces, lo que significa que el área en la que es visible no debe ser trivial.

Probablemente no reescribiera el código que hizo esto, pero parece una mala costumbre entrar.

9

IMO, el problema con los antipatrones de Java es que fomentan el pensamiento en blanco y negro.

En realidad, la mayoría de los antipatrones tienen matices. Por ejemplo, el artículo vinculado explica cómo pseudo-typedefs conduce a API cuyas firmas de tipo son demasiado restrictivas, demasiado ligadas a decisiones de implementación particulares, virales, etc. Pero todo esto está en el contexto de las API públicas. Si mantiene los pseudo-typedefs fuera de las API públicas (es decir, los restringe a una clase, o tal vez a un módulo), es probable que no causen daños reales y que pueden hacer que su código sea más legible.

Mi punto es que usted necesita para comprender los anti-patrones y hacer un juicio razonado sobre cuándo y dónde para evitarlos. Simplemente tomar la posición de que "lo haré nunca do X porque es un antipatrón" significa que a veces se descartarán soluciones aceptables o incluso buenas.

Cuestiones relacionadas