Я хотел бы закодировать очень модульную фабрику с использованием интерфейса поставщика услуг, поэтому без необходимости изменять каждый раз, когда сама фабрика.
Чтобы сделать это, я хотел бы получить список всех Concrete Classes, которые реализуют интерфейс, и решать во время выполнения, какой из них использовать при вызове метода в каждом, пока у меня не будет подходящего исполнителя.
Пример: у меня есть interface Poligon
и Class Triangle implements Poligon
Concrete Class Triangle implements Poligon
. Дискриминационным методом будет:
boolean isSuitableFor(int i) {
if (i == 3)
return true;
else
return false;
}
В Java SE я могу сделать это с помощью ServiceLoader: в среде Enterprise, как я могу найти весь класс реализации и во время выполнения, решите использовать его реализацию, если это подходит? Спасибо!
Есть несколько способов решить эту проблему с помощью CDI.
Во-первых, если метод isSuitableFor
так же прост, как вы перечисляете, вы можете использовать Qualifier
с значением @Nonbinding
для указанного в списке int и просто искать реализацию с этим значением классификатора. Скажем, что определитель является @Vertices
а значение для Triangle
равно 3
, поэтому квалификатор становится:
@Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Vertices {
@Nonbinding int value();
}
И Треугольник становится:
@Vertices(3)
public class Triangle implements Polygon{
}
И вы получите ссылку на него через:
@Inject
@Vertices(3)
private Polygon polygon;
Или вы можете создать AnnotationLiteral
для вершин и вручную просмотреть его через экземпляр.
Другой способ - перебрать все экземпляры, например:
@Inject
@Any
private Instance<Polygon> polygons;
for(Polygon p : polygons) {
if(p.isSuitableFor(x)) {
// do something.
}
}
Это предполагает, что все многоугольники являются зарегистрированными бобами. Это будет медленным для большого числа полигонов.
Третий способ - использовать событие, а не квалифицировать класс, квалифицировать метод наблюдателя. Например
@Inject
private Event<SomePayload> somePayload;
// later on
somePayload.select(new VerticesLiteral(3)).fire(somePayload);
// and the observer method in Triangle
public void handle(@Observes @Vertices(3) SomePayload somePayload) { ... }
// and in square
public void handle(@Observes @Vertices(4) SomePayload somePayload) { ... }