Вообщем по просьбе Viktor Davion объясняю (в 140 твиттеровских символов не уложился), отчасти, что побудило к посту ненависти. Под катом, т.к. содержит плоды работы воспалённого мозга.
Вот набросок того кода, который побудил этот пост (упрощённый, по памяти):
- package me.drobushevich.blog.generics;
- public abstract class AbstractWorker {
- public abstract void execute();
- }
- package me.drobushevich.blog.generics;
- public class Config {
- public final String name;
- public Config(final String name) {
- this.name = name;
- }
- }
- package me.drobushevich.blog.generics;
- public abstract class AbstractWorkerFactory<C extends Config> {
- public abstract AbstractWorker createWorker(final C configuration);
- }
- package me.drobushevich.blog.generics;
- import java.util.ArrayList;
- import java.util.List;
- public class Service {
- private final List<AbstractWorker> workers;
- public Service(final AbstractWorkerFactory<? extends Config> factory, List<Config> configurations) {
- workers = new ArrayList<AbstractWorker>();
- for (Config configuration : configurations) {
- // не компилится The method createWorker(capture#1-of ? extends Config) in the type AbstractWorkerFactory<capture#1-of ? extends Config> is not applicable for the arguments (Config)
- workers.add(factory.createWorker(configuration));
- }
- }
- }
Всё очень просто, фабрика, которая по Generic конфигурации строит объекты. Сервису должно быть пофигу безразлично, что за конфигурация и т.п. Сервис выглядит странно, т.к. можно было просто передать набор работников, но так надо, тащить все зависимости в блог лениво.
Вроде ж выглядит логично, create метод принимает потомка конфигурации, мы потомка конфигурации и даём...
Маленькие пометки.
Зачем вообще дженерики О.о Просто для маленьких вкусностей, вот таких:
- package me.drobushevich.blog.generics;
- public class ReadConfig extends Config {
- public final boolean option;
- public ReadConfig(final String name, final boolean option) {
- super(name);
- this.option = option;
- }
- }
- package me.drobushevich.blog.generics;
- public class ReadWorker extends AbstractWorker {
- public ReadWorker(final boolean option) {
- }
- @Override
- public void execute() {
- }
- }
- package me.drobushevich.blog.generics;
- public class ReadWorkerFactory extends AbstractWorkerFactory<ReadConfig> {
- @Override
- public AbstractWorker createWorker(final ReadConfig configuration) {
- // Обратим внимание на эту строчку (:
- return new ReadWorker(configuration.option);
- }
- }
Проблему можно в принципе решить например вот так:
- public Service(final AbstractWorkerFactory<Config> factory, final List<Config> configurations) {
- // но не работает
- new Service(new ReadWorkerFactory(), configurations);
Вообщем жду предложений (; Не исключается возможность ошибки в ДНК. В последнее время за мной было замечено предложение не самых здравых идей ):
Главная проблема, что Generics это уровень компиляции, jvm о них ничего не знает. Кстати, можно посмотреть не очень давнее выступление Джеймса Гослинга, в частности он там говорит, что Generics были реализованы как компромисс между усложнением и полезностью. Трудно спорить (: особенно с ним (:
Кстати, там же он хвалит Scala, вот где, мне нравятся generics, так это в там (к самому языку отношусь не так, хотя тот факт, что на нём можно писать так как на java, но с доп. плюшками, это не плохо).
Если будет настроение, на выходных напишу пост о Generics в Scala. Всё таки generics высших порядков это звучит интересно (:
UPDATE (после обсуждения на stackoverflow):
- public AbstractWorker caramba(final AbstractWorkerFactory<? super ReadConfig> factory, ReadConfig configuration) {
- return factory.createWorker(configuration);
- }
- new Service().caramba(new WorkerFactory(), new ReadConfig("1", false));
- new Service().caramba(new ReadWorkerFactory(), new ReadConfig("2", true));