2011-03-26 8 views
5

Tengo más de 10 clases y cada una tiene LUMP_INDEX y SIZE constante estática. Quiero una matriz de cada una de estas clases, donde el tamaño de la matriz se calcula utilizando esas dos constantes. En el momento en que tienen una función para cada clase para crear la matriz, algo a lo largo de las líneas de:Deduplicar esta duplicación de código Java

private Plane[] readPlanes() 
{ 
    int count = header.lumps[Plane.LUMP_INDEX].filelen/Plane.SIZE; 
    Plane[] planes = new Plane[count]; 
    for(int i = 0; i < count; i++) 
     planes[i] = new Plane(); 

    return planes; 
} 

private Node[] readNodes() 
{ 
    int count = header.lumps[Node.LUMP_INDEX].filelen/Node.SIZE; 
    Node[] nodes = new Node[count]; 
    for(int i = 0; i < count; i++) 
     nodes[i] = new Node(); 

    return nodes; 
} 

private Leaf[] readLeaves() 
{ 
    int count = header.lumps[Leaf.LUMP_INDEX].filelen/Leaf.SIZE; 
    Leaf[] leaves = new Leaf[count]; 
    for(int i = 0; i < count; i++) 
     leaves[i] = new Leaf(); 

    return leaves; 
} 

etc. Hay 10 de estas funciones, y las únicas diferencias son el tipo de clase, con el fin usted puede ver, hay una tonelada de duplicación.

¿Alguien tiene alguna idea sobre cómo evitar esta duplicación? Gracias. (Hice una pregunta similar antes, pero supongo que la forma en que pregunté fue un poco)

+0

¿Tiene declaraciones de devolución en métodos vacíos? –

+0

¿cuál es el objeto 'header' en estos métodos? –

+0

¿Por qué no usarías una ArrayList? – bancer

Respuesta

1

Okey doke ... He probado esto para asegurarme, y creo que hace lo que está buscando.

Hace falta un programa de interfaz:

public interface MyInterface 
{ 
    public int getSize(); 
    public int getLumpIndex(); 
} 

Sus clases implementan esa interfaz:

public class Plane implements MyInterface 
{ 

    ... 
    public int getSize() 
    { 
     return SIZE; 
    } 

    public int getLumpIndex() 
    { 
     return LUMP_INDEX; 
    } 

} 

En la clase que header es una instancia de, usted tiene ...

public <E extends MyInterface> E[] 
    getArray(Class<E> c, MyInterface foo) 
{ 
    int count = lumps[foo.getLumpIndex()].filelen/foo.getSize(); 
    E[] myArray = (E[]) Array.newInstance(c, count); 
    for(int i = 0; i < count; i++) 
     myArray[i] = c.newInstance(); 
    return myArray; 
} 

Puedes llamarlo desde, por ejemplo, tu clase de plano como:

Plane[] p = header.getArray(Plane.class, this); 

I pensar? :) ¿Alguien puede ver esto y ver si estoy fuera?

(EDIT: robaba he probado ahora - que funciona)

En una nota adicional, que podría eliminar los captadores en cada clase, haciendo getArray() tomar el tamaño y el índice como argumentos:

public <E extends MyInterface> E[] 
    getArray(Class<E> c, int size, int index) 
{ 
    int count = lumps[index].filelen/size; 
    E[] myArray = (E[]) Array.newInstance(c, count); 
    for(int i = 0; i < count; i++) 
     myArray[i] = c.newInstance(); 
    return myArray; 
} 

y llamarlo como:

Plane p[] = header.getArray(Plane.class, SIZE, LUMP_INDEX); 

desde el interior de sus clases. La interfaz simplemente se vuelve vacía para proporcionar el tipo genérico y no es necesario definir los métodos getter.

O (última edición que promete, pero esto no le dan opciones y explica un poco acerca de los genéricos)

Zanja la interfaz. Lo que esto elimina la comprobación es un poco de cordura porque el método no le importa qué tipo de objeto se le da:

public <E> E[] 
    getArray(Class<E> c, int size, int index) 
{ 
    ... 

Ahora usted no tiene que definir la interfaz o ponerlo en práctica, que acaba de llamar:

Plane p[] = header.getArray(Plane.class, SIZE, LUMP_INDEX); 
+0

Gracias, creo que esa es probablemente la mejor manera de hacerlo (excepto que la función getArray no necesita estar dentro del encabezado). Sin embargo, cuando lo intento, c.newInstance() arroja una InstantiationException, y no tengo idea de por qué, así que estoy perplejo. – terryhau

+0

Nunca has publicado lo que tus constructores fueron para tus objetos. ¿Tienes un constructor sin argumentos? –

+0

Sí, no tienen argumentos. He descubierto por qué está lanzando la excepción. Gracias – terryhau

3

Use Java generics. De esta forma, puede simplemente escribir un método genérico y especificar un parámetro de tipo cada vez que lo use.

+0

te refieres a algo como privado lectura nula (clase clazz)? No puedo acceder a las 2 constantes a través del parámetro clazz. – terryhau

+2

Tenga en cuenta que no puede hacer 'new T [x]' con genéricos. Usted * puede * evitarlo, pero la respuesta no es tan simple. –

+0

@Brian Roach: ¿una pista sobre qué usar entonces? Un contenedor genérico? – xtofl

0

uso de genéricos, sino que tendrá que pasar en algún tipo de objeto de fábrica para construir instancias para poner en su colección, por ejemplo: solución

public class MyClass { 

public <E> E[] getArray(IObjectFactory builder, int index, int size){ 
    ArrayList<E> arrayList = new ArrayList<E>(); 
    int count = header.lumps[index].filelen/size;//wasn'tsure where header was coming from... 
    for(int i = 0; i< count; i++){ 
     E newInstance = builder.getNewInstance(); 
     arrayList.add(newInstance); 
    } 
    return (E[]) arrayList.toArray(); 
    } 
}  

interface IObjectFactory { 
<E> E getNewInstance(); 
} 
2

de Bala está cerca. Sin embargo, no puede acceder a las constantes del tipo genérico, así que crearía un getCount() (o lo que sea que quiera nombrarlo) y cada subtipo lo implementará con las constantes apropiadas.

interface LumpySize<L extends LumpySize> { 
    int getCount(); // subtypes return the appropriate header.lumps[Plane.LUMP_INDEX].filelen/Plane.SIZE; 

    T[] initializeArray(); 

    abstract <T extends LumpySize> static class Base implements LumpySize<T> { 
     protected T[] initializeArray(Class<T> cls) { 
      int count = getCount(); 
      T[] lumps = (T[]) Array.newInstance(cls, count); 
      for(int i = 0; i < count; i++) { 
       try { 
        lumps[i] = cls.newInstance(); 
       } catch (Exception e) { // obviously this isn't good practice. 
        throw new RuntimeException(e); 
       } 
      } 
      return lumps; 
     }  
    }    
} 

class Plane extends LumpySize.Base<Plane> { 
    public int getCount() { 
     return header.lumps[Plane.LUMP_INDEX].filelen/Plane.SIZE; // assuming header is available somewhere 
    } 
    public Plane[] initializeArray() { return initializeArray(Plane.class); } 
} 
+0

Has leído mal el código. Es una clase base abstracta que extiendes, por ejemplo, 'la clase Plano extiende LumpySize.Base '. –

+0

Doh, lo siento, lo leí mal. Borrando mi comentario –

+0

+1. Sí. Esa es la forma de obtener constantes dependientes de la implementación en código genérico. Muy útil para saber – extraneon

Cuestiones relacionadas