Дублируйте это дублирование кода Java - PullRequest
5 голосов
/ 26 марта 2011

У меня около 10+ классов, и у каждого из них есть статическая константа LUMP_INDEX и SIZE.Я хочу массив каждого из этих классов, где размер массива рассчитывается с использованием этих двух констант.На данный момент у меня есть функция для каждого класса для создания массива, что-то вроде:

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;
}

и т. Д.Существует 10 таких функций, и единственное различие заключается в типе класса, так что, как вы видите, существует множество дубликатов.

Есть ли у кого-нибудь идеи, как избежать этого дублирования?Благодарю.(Я задавал подобный вопрос раньше, но, думаю, то, как я его спросил, было немного не так)

Ответы [ 4 ]

3 голосов
/ 26 марта 2011

Использовать Обобщения Java .Таким образом, вы можете просто написать один универсальный метод и указывать параметр типа каждый раз, когда вы его используете.

2 голосов
/ 26 марта 2011

Решение Балы близко. Вы не можете получить доступ к константам из универсального типа, поэтому я бы создал getCount () (или как вы хотите его назвать), и чтобы каждый подтип реализовывал его с соответствующими константами.

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); }
}
1 голос
/ 26 марта 2011

Да ладно ... Я проверил это, чтобы убедиться, и я верю, что он делает то, что вы ищете.

Вам нужен интерфейс:

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

Ваши классы реализуют этот интерфейс:

public class Plane implements MyInterface
{

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

    public int getLumpIndex()
    {
        return LUMP_INDEX;
    }

}

В классе, экземпляром которого является header, у вас есть ...

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;
}

Вы можете назвать это, скажем, классом вашего самолета как:

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

Я думаю ? :) Может кто-то посмотреть на это и посмотреть, если я выключен?

( РЕДАКТИРОВАТЬ: Becasue я проверил это сейчас - это работает)

На дополнительном примечании вы можете исключить методы получения в каждом классе, заставив getArray() принять размер и индекс в качестве аргументов:

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;
}

И назовите его так:

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

из ваших классов. Интерфейс просто становится пустым для предоставления универсального типа, и вам не нужно определять методы получения.

ИЛИ (последнее редактирование обещаю, но это дает вам выбор и объясняет немного о дженериках)

Угробить интерфейс. Это удаляет некоторую проверку работоспособности, потому что методу не важно, какой тип объекта вы ему дадите:

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

Теперь вам не нужно определять интерфейс или реализовывать его, вы просто звоните:

Plane p[] = header.getArray(Plane.class, SIZE, LUMP_INDEX);
0 голосов
/ 26 марта 2011

Используйте дженерики, но вам нужно будет передать какой-то фабричный объект для создания экземпляров для помещения в вашу коллекцию, например:

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();
}
...