Самый эффективный способ создания большого количества подклассов в Java? - PullRequest
0 голосов
/ 20 ноября 2018

Я работаю над проектом, который требует использования большого количества объектов классов, расширяющих определенный абстрактный класс.Для создания вручную требуется вызов отдельного конструктора каждого объекта, который начинает загрязнять мой клиентский класс.

Необработанный код проекта слишком длинный, чтобы публиковать его на этом сайте, поэтому ниже приведен упрощенный пример:

Предположим, что существует абстрактный класс Letter:

public abstract class Letter{
    String letter;
}

И 26 отдельных буквенных классов, расширяющих абстрактный класс Letter:

public class A extends Letter{
    this.letter = "A";
}

public class B extends Letter{
    this.letter = "B";
}
... and so on

Здесь я обращаюсь за помощью.- Существует класс клиента с именем Alphabet:

public class Alphabet{
    public List<Letter> getLetters(){
        List<Letter> letters = new ArrayList<>();
        A a = new A();
        B b = new B();
        C c = new C();
        list.add(a);
        list.add(b);
        list.add(c);
        ...the list goes on

        return letters;
    }
}

Как видите, создание каждой буквы вручную не идеально.Я ищу способ для динамического создания списка объектов класса во время выполнения.

Возможно, что-то похожее на это:

public class Alphabet{
    public List<Letter> getLetters(){
        List<Letter> letters = getAllClassesExtending(Letter.class);
        return letters;
        //list would then contain A,B,C,D,E,F,G, etc.
    }
}

В конечном итоге я хочу иметь возможность создать новый класс и автоматически добавить его в список объектов в клиентском классе,без необходимости изменять клиентский класс (например, я не хочу явно ссылаться на каждый буквенный класс в клиентском классе).

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Это похоже на типичный вариант использования enum.Константы enum могут иметь тело класса с кодом, переопределяя методы базового типа и даже объявлять новые поля.

Задача получения экземпляра всех подтипов подразумевает закрытый набор подтипов,что соответствует поведению enum типов.

public enum Letter {
    A {
        @Override
        public boolean isVowel() {
            return true;
        }
    },
    B, C, D,
    E {
        @Override
        public boolean isVowel() {
            return true;
        }
    },
    F, G, H,
    I {
        @Override
        public boolean isVowel() {
            return true;
        }
    }, J, K, L, M, N,
    O {
        @Override
        public boolean isVowel() {
            return true;
        }
    }, P, Q, R, S, T,
    U {
        @Override
        public boolean isVowel() {
            return true;
        }
    }, V, W, X, Y, Z;
    ;
    String letter = name();

    public static List<Letter> getLetters() {
        return Arrays.asList(values());
    }

    public boolean isVowel() {
        return false;
    }
}

Это демонстрирует, что переопределение методов возможно, а также метод для получения всех экземпляров (в виде массива) предоставляется бесплатно.Кроме того, имена задаются по своей сути без избыточности.

Если вы хотите иметь вместо этого открытый набор подклассов, который может быть расширен после компиляции кода, вам следует взглянуть на концепцию Service Provider и ServiceLoader класс.Этот механизм не будет автоматически находить подклассы, а только те, которые объявлены в качестве поставщиков услуг либо в файле в META-INF, либо через декларацию модуля, с другой стороны, он предоставляет вам надежное, устоявшееся решение, которое будет поддерживаться разработчиками Javaили даже развиваться вместе с платформой, как интеграция в концепцию новых модулей.

0 голосов
/ 21 ноября 2018

Вы можете использовать библиотеку Reflections , чтобы найти классы во время выполнения, например, если все они находятся в пакете com.letters и имеют конструктор без аргументов:

public List<? extends Letter> getLetters(){
  Reflections reflections = new Reflections("com.letters");
  Set<Class<? extends Letter>> classes = reflections.getSubTypesOf(Letter.class);
  return classes.stream()
        .map(clazz -> {
            try {
                return clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException ex) {
                throw new RuntimeException(ex);
            }
        })
        .collect(Collectors.toList());
}

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

...