Как использовать новый экземпляр для создания класса, который требует параметров? - PullRequest
2 голосов
/ 20 января 2010

Я понимаю, что вы можете создать новый класс с параметрами из строки со следующей конструкцией:

Class<? extends Base> newClass = (Class<? extends Base>)Class.forName(className);
Constructor<? extends Base> c = newClass.getConstructor(new Class[] {Manager.class, Integer.TYPE});
Base a = c.newInstance(new Object[] {this, new Integer(0)});

Но я не верю, что есть способ гарантировать, что подклассы Base реализуют используемый конструктор.

Есть ли практика для обработки этой ситуации?

Ответы [ 4 ]

2 голосов
/ 20 января 2010

@ axtavt прав.Вы не можете заставить подкласс предоставлять конструкторам определенные подписи.(В неотражающем случае нет никакого смысла, потому что конструкторы Java не являются полиморфными. И отражение всегда немного ... некрасиво.)

Если вы хотите создать полиморфный объект, вы можетеиспользуйте шаблон Factory.

public interface BaseFactory {
    Base create(int arg1, String arg2);
    Base create(int arg1, float arg2);
}

public class Foo implements Base { .... }

public class FooFactory implements BaseFactory {
    public Base create(int arg1, String arg2) {
        return new Foo(arg1, arg2);
    }
    public Base create(int arg1, float arg2) {
        return new Foo(arg1, Float.toString(arg2));
    }
}

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

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

2 голосов
/ 20 января 2010

Если параметры являются фиксированными, и вы хотите использовать newInstance, у вас остается проблема, заключающаяся в том, что вы не можете обеспечить существование соответствующего конструктора в подклассе. Если вы хотите, чтобы компилятор проверил это, вы можете использовать фабричный класс для перехода между ними: Определите фабричный интерфейс, имеющий createInstance с нужными параметрами, и вместо прямой регистрации подкласса зарегистрируйте Фабрика, которая производит это:

Class<? extends BaseFactory> newClass = 
      (Class<? extends BaseFactory>)Class.forName(factoryClassNameName);
BaseFactory factory = newClass.getInstance();
Base a = factory.createInstance(this, 0);  // no reflection necessary here

Если вам нужно создать экземпляры объектов из строк конфигурации, и все может стать более сложным, чем простой вызов newInstance с фиксированным числом параметров, вам следует взглянуть на DI-контейнеры. Все это позволяет создавать экземпляры несколькими очень гибкими способами, в том числе с использованием параметров, которые сами являются сложными объектами (которые вам будет сложно кодировать в виде плоской строки).

Срединный план использует свойства для настройки экземпляров. Посмотрите, например, как структуры ведения журналов настраивают различные компоненты, используя файл свойств.

2 голосов
/ 20 января 2010

Нет способа обеспечить реализацию конкретного конструктора подклассами. Если вы являетесь автором класса Base, вы можете объявить некоторый метод init(Manager, int) вместо использования конструктора с параметрами.

1 голос
/ 20 января 2010

Конструкторы не похожи на обычные методы: вы не можете объявить абстрактный конструктор, который должен реализовать дочерний элемент. Другими словами, вы не можете определить, каким образом может быть создан дочерний класс. В философии ОО это не входит в обязанности базового класса.

Если вы хотите, вы можете создать абстрактный метод инициализации, как предложил axtavt, и вызвать его из конструктора вашего базового класса. Тогда вы, по крайней мере, знаете, что ему позвонят.

Вы также можете проверить конструктор с нужной подписью. Если вы не найдете его, вы можете выдать исключение о том, что класс не соответствует вашим условиям. Таким образом, рефлексия может дать вам немного больше силы, чем встроено в язык.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...