Как вы уже отметили, ни одна из трех идей в вопросе не поддерживается (конструктор с сертификатом в сигнатуре в интерфейсе, абстрактный класс, обеспечивающий выполнение определенного конструктора, или статический метод в интерфейсе или абстрактном классе)
Однако вы можете определить интерфейс (или абстрактный класс), который является Factory для типа, который вы в конечном счете, хотят.
public interface AnInterface {
int fancyComputation();
}
public interface IFooBarFactory<T extends AnInterface> {
T create(int magicNumber);
}
IFooBarFactory имеет 2 конкретных реализаций
public class BarFactory implements IFooBarFactory<Bar> {
public Bar create(int magicNumber) {
return new Bar(magicNumber);
}
}
public class FooFactory implements IFooBarFactory<Foo> {
public Foo create(int magicNumber) {
return new Foo(magicNumber);
}
}
Затем использовать шаблон стратегии (https://en.wikipedia.org/wiki/Strategy_pattern), чтобы получить правильный завод. Затем используйте эту фабрику, которая имеет известный интерфейс, для создания вашего объекта с правильным значением (и любыми дополнительными значениями, необходимыми для изготовления объекта).
FooBarFactory fooBarFactory = new FooBarFactory();
IFooBarFactory<T> factory = fooBarFactory.createFactory(typeOfAnInterface);
T impl = factory.create(magicNumber);
С конкретными видами реализации
public class Bar implements AnInterface {
private final int magicInt;
public Bar(int magicInt) {
this.magicInt = magicInt;
}
public int fancyComputation() {
return magicInt + 2;
}
}
public class Foo implements AnInterface {
private final int magicInt;
public Foo(int magicInt) {
this.magicInt = magicInt;
}
public int fancyComputation() {
return magicInt + 1;
}
}
следующий код:
public static void main(String ... parameters) {
test(Foo.class);
test(Bar.class);
}
private static <T extends AnInterface> void test(Class<T> typeOfAnInterface) {
T impl = createImplForAnInterface(typeOfAnInterface, 10);
System.out.println(typeOfAnInterface.getName() + " produced " + impl.fancyComputation());
}
private static <T extends AnInterface> T createImplForAnInterface(Class<T> typeOfAnInterface, int magicNumber) {
FooBarFactory fooBarFactory = new FooBarFactory();
IFooBarFactory<T> factory = fooBarFactory.createFactory(typeOfAnInterface);
T impl = factory.create(magicNumber);
return impl;
}
печатает
Foo produced 11
Bar produced 12
Это обеспечивает ряд преимуществ по сравнению с раствором с самоанализом O r статических заводов. Вызывающему не нужно знать, как изготовить какой-либо из объектов, а также не нужно, чтобы вызывающий вызывал необходимость знать или ухаживать, когда метод является «правильным» методом, используемым для получения правильного типа. Все вызывающие абоненты просто называют один общедоступный/известный компонент, который возвращает «правильную» фабрику. Это делает ваших абонентов более чистыми, потому что они больше не тесно связаны с конкретными реализациями AnInterface для типов FooBar. Им нужно только заботиться о «Мне нужна реализация AnInterface, которая потребляет (или обрабатывает) этот тип». Я знаю, что это означает, что у вас есть два «фабричных» класса. Один для получения правильной фабрики, а другой - для создания конкретных типов Foo и Bar. Однако вы скрываете эту деталь реализации от вызывающих абонентов через дополнительный слой абстракции (см. Метод createImplForAnInterface).
Этот подход будет особенно полезен, если вы обычно используете некоторую форму инъекции зависимости. Моя рекомендация в точности соответствует приложению, полученному от Guice (https://github.com/google/guice/wiki/AssistedInject) или аналогичной идее весной (Is it possible and how to do Assisted Injection in Spring?).
Это означает, что вам нужно иметь несколько фабричных классов (или правила привязки вложений для Guice), но каждый из этих классов является небольшим, простым и простым в обслуживании. Затем вы пишете небольшой тест, который извлекает все классы, которые реализуют AnInterface, и вы проверяете, что ваш компонент, который реализует шаблон стратегии, охватывает все случаи (через отражение - я бы использовал класс Reflections в org.reflections: reflections).Это дает вам полезную абстракцию кода, которая упрощает использование этих объектов за счет сокращения избыточного кода, ослабления жесткой связи компонентов и не жертвуя полиморфизмом.
Я не понимаю, в чем ваш вопрос ... Что именно вы пытаетесь достичь и почему это не работает? –
Я думаю, что в вашем желаемом коде результата есть что-то странное. 'SampleSource' имеет параметр, который расширяет' SampleFactory'. Затем в 'getCurrentSample()' вы вызываете эту фабрику образцов для создания образца, который должен иметь тот же тип, что и 'SampleFactory'. Итак, создание образца дает вам образец фабрики? – Timo
Ну, так как в интерфейсах допускаются статические методы Java 8. – Flown