Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DI:依存性注入ライブラリを自分で作ろう

 DI:依存性注入ライブラリを自分で作ろう

DI は便利だけど、@Injectはどこに付けたらいい?どの場合に付けたらいい?@Singletonは?
それから、うまく行かなかった場合は調査するの大変?
Dependency Injection はブラックボックスにみえるかもしれないけどやっている事はシンプル。
ステップ・バイ・ステップ、依存性注入ライブラリをどうやって作るかをみましょう。

Benoît Quenaudon

August 02, 2017
Tweet

More Decks by Benoît Quenaudon

Other Decks in Programming

Transcript

  1. public class VisitHandler { private final Counter counter; private final

    Logger logger; public VisitHandler(Counter counter, Logger logger) { this.counter = counter; this.logger = logger; } public void visit() { counter.increment(); logger.log("Visits increased: " + counter.getCount()); } }
  2. public class Counter { private int count; void increment() {

    count++; } int getCount() { return count; } } public class Logger { private final PrintStream printStream; public Logger(PrintStream printStream) { this.printStream = printStream; } public void log(String log) { printStream.println(log); } }
  3. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  4. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  5. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  6. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  7. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  8. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  9. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); }
  10. public class ObjectGraph { public <T> T get(Class<T> key) {

    throw new UnsupportedOperationException("Not implemented"); } }
  11. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  12. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  13. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  14. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  15. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  16. public class ObjectGraph { private final Linker linker; public ObjectGraph(Linker

    linker) { this.linker = linker; } public <T> T get(Class<T> key) { Factory<T> factory = linker.factoryFor(key); return factory.get(linker); } }
  17. public class ObjectGraph { private final Linker linker; public ObjectGraph(Linker

    linker) { this.linker = linker; } public <T> T get(Class<T> key) { Factory<T> factory = linker.factoryFor(key); return factory.get(linker); } }
  18. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); }
  19. private static ObjectGraph buildObjectGraph() { Linker linker = new Linker();

    installFactories(linker); return new ObjectGraph(linker); }
  20. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); }
  21. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); }
  22. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); }
  23. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); }
  24. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() {
  25. Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger

    = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() { @Override public PrintStream get(Linker linker) { return System.out; } }); linker.install(Counter.class, new Factory<Counter>() {
  26. Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger

    = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() { @Override public PrintStream get(Linker linker) { return System.out; } }); linker.install(Counter.class, new Factory<Counter>() {
  27. Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger

    = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() { @Override public PrintStream get(Linker linker) { return System.out; } }); linker.install(Counter.class, new Factory<Counter>() {
  28. linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) {

    Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() { @Override public PrintStream get(Linker linker) { return System.out; } }); linker.install(Counter.class, new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } }); }
  29. linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) {

    Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } }); }
  30. public class ValueFactory<T> implements Factory<T> { public static <T> Factory<T>

    of(T instance) { return new ValueFactory<>(instance); } private final T value; public ValueFactory(T value) { this.value = value; } @Override public T get(Linker linker) { return value; } }
  31. Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } });

    linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } }); }
  32. Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } });

    linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } }); }
  33. Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } });

    linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } })); }
  34. public class SingletonFactory<T> implements Factory<T> { public static <T> Factory<T>

    of(Factory<T> factory) { return new SingletonFactory<>(factory); } private final Factory<T> factory; private T instance; public SingletonFactory(Factory<T> factory) { this.factory = factory; } @Override public T get(Linker linker) { if (instance == null) { instance = factory.get(linker); } return instance; } }
  35. public class SingletonFactory<T> implements Factory<T> { public static <T> Factory<T>

    of(Factory<T> factory) { return new SingletonFactory<>(factory); } private final Factory<T> factory; private T instance; public SingletonFactory(Factory<T> factory) { this.factory = factory; } @Override public T get(Linker linker) { if (instance == null) { instance = factory.get(linker); } return instance; } }
  36. Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } });

    linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } })); }
  37. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStream); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } })); }
  38. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { System.out.println("Get factory for " + key); return (Factory<T>) factories.get(key); } }
  39. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { System.out.println("Get factory for " + key); return (Factory<T>) factories.get(key); } }
  40. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); } Get factory for class VisitHandler Get factory for class Counter Get factory for class Logger Get factory for class java.io.PrintStream Visits increased: 1
  41. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); VisitHandler visitHandler2 = objectGraph.get(VisitHandler.class); visitHandler2.visit(); } Get factory for class VisitHandler Get factory for class Counter Get factory for class Logger Get factory for class java.io.PrintStream Visits increased: 1 Get factory for class VisitHandler Get factory for class Counter Get factory for class Logger Get factory for class java.io.PrintStream Visits increased: 2
  42. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  43. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  44. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  45. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  46. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  47. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  48. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  49. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  50. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStream); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } })); }
  51. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStream); } }); linker.install(PrintStream.class, ValueFactory.of(System.out));
  52. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);
  53. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);
  54. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);
  55. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);
  56. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { System.out.println("Get factory for " + key); Factory<?> factory = linkedFactories.get(key); if (factory == null) { System.out.println("Link factory for " + key); factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  57. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { System.out.println("Get factory for " + key); Factory<?> factory = linkedFactories.get(key); if (factory == null) { System.out.println("Link factory for " + key); factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  58. Get factory for class VisitHandler Link factory for class VisitHandler

    Get factory for class Counter Link factory for class Counter Get factory for class Logger Link factory for class Logger Get factory for class java.io.PrintStream Link factory for class java.io.PrintStream Visits increased: 1 Get factory for class VisitHandler Visits increased: 2 public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph(); VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); VisitHandler visitHandler2 = objectGraph.get(VisitHandler.class); visitHandler2.visit(); }
  59. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { Factory<PrintStream> printStreamFactory; @Override public void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get() { return new Counter(); } })); }
  60. public class VisitHandler { private final Counter counter; private final

    Logger logger; @Inject public VisitHandler(Counter counter, Logger logger) { this.counter = counter; this.logger = logger; } public void visit() { counter.increment(); logger.log("Visits increased: " + counter.getCount()); } }
  61. public class VisitHandler { private final Counter counter; private final

    Logger logger; @Inject public VisitHandler(Counter counter, Logger logger) { this.counter = counter; this.logger = logger; } public void visit() { counter.increment(); logger.log("Visits increased: " + counter.getCount()); } }
  62. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  63. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  64. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = loadFactory(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  65. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = loadFactory(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  66. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  67. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  68. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  69. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  70. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  71. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  72. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  73. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  74. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  75. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  76. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  77. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  78. public class VisitHandler { @Inject public VisitHandler(Counter counter, Logger logger)

    { this.counter = counter; this.logger = logger; } } public class Logger { @Inject public Logger(PrintStream printStream) { this.printStream = printStream; } } @Singleton public class Counter { @Inject public Counter() {} }
  79. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { Factory<PrintStream> printStreamFactory; @Override public void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get() { return new Counter(); } })); }
  80. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    ... }); linker.install(Logger.class, new Factory<Logger>() { ... }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { ... })); }
  81. private static void installFactories(Linker linker) { linker.install(Logger.class, new Factory<Logger>() {

    ... }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { ... })); }
  82. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { Factory<PrintStream> printStreamFactory; @Override public void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get() { return new Counter(); } })); } private static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  83. linker.install(VisitHandler.class, new Factory<Logger>() { Factory<PrintStream> printStreamFactory; @Override public void link(Linker

    linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } });
  84. public class Logger$$Factory extends Factory<Logger> { Factory<PrintStream> printStreamFactory; @Override public

    void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }
  85. public abstract class GeneratedFactory<T> extends Factory<T> { private final boolean

    singleton; public GeneratedFactory(boolean singleton) { this.singleton = singleton; } } public class Logger$$Factory extends GeneratedFactory<Logger> { public Logger$$Factory() { super(false); } }
  86. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); }
  87. public class Linker { private <T> Factory<?> loadFactory(Class<T> key) {

    Factory<?> factory = factories.get(key); if (factory != null) { return factory; } factory = GeneratedFactory.loadFactory(key); if (factory != null) { return factory; } throw new IllegalStateException("No factory for " + key); } }
  88. public class Linker { private <T> Factory<?> loadFactory(Class<T> key) {

    Factory<?> factory = factories.get(key); if (factory != null) { return factory; } factory = GeneratedFactory.loadFactory(key); if (factory != null) { return factory; } throw new IllegalStateException("No factory for " + key); } }
  89. public abstract class GeneratedFactory<T> extends Factory<T> { public static <T>

    Factory<T> loadFactory(Class<T> key) { String generatedClass = key.getName() + "$$Factory"; try { Class<GeneratedFactory<T>> factoryClass = (Class<GeneratedFactory<T>>) Class.forName(generatedClass); GeneratedFactory<T> factory = factoryClass.newInstance(); if (factory.singleton) { return SingletonFactory.of(factory); } else { return factory; } } catch (Exception e) { System.err.println("Error for " + key); e.printStackTrace(); return null; } } private final boolean singleton; public GeneratedFactory(boolean singleton) { this.singleton = singleton; } }
  90. public abstract class GeneratedFactory<T> extends Factory<T> { public static <T>

    Factory<T> loadFactory(Class<T> key) { String generatedClass = key.getName() + "$$Factory"; try { Class<GeneratedFactory<T>> factoryClass = (Class<GeneratedFactory<T>>) Class.forName(generatedClass); GeneratedFactory<T> factory = factoryClass.newInstance(); if (factory.singleton) { return SingletonFactory.of(factory); } else { return factory; } } catch (Exception e) { System.err.println("Error for " + key); e.printStackTrace(); return null; } } private final boolean singleton; public GeneratedFactory(boolean singleton) { this.singleton = singleton; } }
  91. public abstract class GeneratedFactory<T> extends Factory<T> { public static <T>

    Factory<T> loadFactory(Class<T> key) { String generatedClass = key.getName() + "$$Factory"; try { Class<GeneratedFactory<T>> factoryClass = (Class<GeneratedFactory<T>>) Class.forName(generatedClass); GeneratedFactory<T> factory = factoryClass.newInstance(); if (factory.singleton) { return SingletonFactory.of(factory); } else { return factory; } } catch (Exception e) { System.err.println("Error for " + key); e.printStackTrace(); return null; } } private final boolean singleton; public GeneratedFactory(boolean singleton) { this.singleton = singleton; } }
  92. public class DatabaseManager { private final Database database; @Inject public

    DatabaseManager(Database database) { this.database = database; } public void updateVisits(int count) { database.execute("UPDATE count_table SET count = " + count); } }
  93. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    DatabaseManager databaseManager = objectGraph.get(DatabaseManager.class); databaseManager.updateVisits(3); } Exception in thread "main" java.lang.IllegalStateException: No factory for interface app.db.Database at injection.Linker.loadFactory(Linker.java:41) at injection.Linker.factoryFor(Linker.java:21) at app.db.DatabaseManager$$Factory.link(DatabaseManager$$Factory.java:17) at injection.factory.SingletonFactory.link(SingletonFactory.java:20) at injection.Linker.factoryFor(Linker.java:22) at injection.ObjectGraph.get(ObjectGraph.java:13) at Main.main(Main.java:11)
  94. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    objectGraph.validate(DatabaseManager.class); DatabaseManager databaseManager = objectGraph.get(DatabaseManager.class); databaseManager.updateVisits(3); } public class ObjectGraph { private final Linker linker; public <T> T get(Class<T> key) { Factory<T> factory = linker.factoryFor(key); return factory.get(); } public <T> void validate(Class<T> key) { linker.factoryFor(key); } }
  95. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    objectGraph.validate(DatabaseManager.class); DatabaseManager databaseManager = objectGraph.get(DatabaseManager.class); databaseManager.updateVisits(3); } public class ObjectGraph { private final Linker linker; public <T> T get(Class<T> key) { Factory<T> factory = linker.factoryFor(key); return factory.get(); } public <T> void validate(Class<T> key) { linker.factoryFor(key); } }
  96. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    objectGraph.validate(DatabaseManager.class); // … } public static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  97. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    objectGraph.validate(DatabaseManager.class); // … } public static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  98. public class Module { @Provides public Database provideDatabase(DatabaseImpl database) {

    return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  99. public class Module { @Provides public Database provideDatabase(DatabaseImpl database) {

    return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  100. @Module public class MainModule { @Provides public Database provideDatabase(DatabaseImpl database)

    { return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  101. private static ObjectGraph buildObjectGraph() { Linker linker = new Linker();

    installFactories(linker); return new ObjectGraph(linker); } private static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  102. private static ObjectGraph buildObjectGraph(List<Class> moduleClasses) { Linker linker = new

    Linker(); linker.loadModuleBindings(moduleClasses); return new ObjectGraph(linker); } private static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  103. @Module public class MainModule { @Provides public Database provideDatabase(DatabaseImpl database)

    { return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  104. @Module public class MainModule { @Provides public Database provideDatabase(DatabaseImpl database)

    { return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  105. @Module(injects = DatabaseManager.class) public class MainModule { @Provides public Database

    provideDatabase(DatabaseImpl database) { return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  106. So far • Instantiation and its order automated • Caching

    • No boilerplate • No reflection • Verification at compile time
  107. public class ObjectGraph { final Linker linker; final ObjectGraph parentGraph;

    public <T> T get(Class<T> key) { if (parentGraph != null) { T instance = parentGraph.get(key); if (instance != null) { return instance; } } Factory<T> factory = linker.factoryFor(key); return factory.get(); } }
  108. public class ObjectGraph { final Linker linker; final ObjectGraph parentGraph;

    public <T> T get(Class<T> key) { if (parentGraph != null) { T instance = parentGraph.get(key); if (instance != null) { return instance; } } Factory<T> factory = linker.factoryFor(key); return factory.get(); } }
  109. public class ObjectGraph { final Linker linker; final ObjectGraph parentGraph;

    public <T> T get(Class<T> key) { if (parentGraph != null) { T instance = parentGraph.get(key); if (instance != null) { return instance; } } Factory<T> factory = linker.factoryFor(key); return factory.get(); } }
  110. public class ObjectGraph { final Linker linker; final ObjectGraph parentGraph;

    public <T> T get(Class<T> key) { if (parentGraph != null) { T instance = parentGraph.get(key); if (instance != null) { return instance; } } Factory<T> factory = linker.factoryFor(key); return factory.get(); } }
  111. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = loadFactory(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  112. So far • Instantiation and its order automated • Caching

    • No boilerplate • No reflection • Verification at compile time • Scope
  113. public class Logger$$Factory extends GeneratedFactory<Logger> { private Factory<PrintStream> printStreamFactory; public

    Logger$$Factory() {} @Override public void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }
  114. public class Logger$$Factory extends GeneratedFactory<Logger> { private Factory<PrintStream> printStreamFactory; public

    Logger$$Factory() {} @Override public Logger get() { return new Logger(printStreamFactory.get()); } }
  115. public class Logger$$Factory extends GeneratedFactory<Logger> { private final Factory<PrintStream> printStreamFactory;

    public Logger$$Factory(Factory<PrintStream> printStreamFactory) { this.printStreamFactory = printStreamFactory; } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }
  116. @Module(injects = DatabaseManager.class) public class MainModule { @Provides public Database

    provideDatabase(DatabaseImpl database) { return database; } @Provides public PrintStream providePrintStream() { return System.out; } } @Component(modules = MainModule.class) public interface MainComponent { DatabaseManager databaseManager(); }
  117. @Module public class MainModule { @Provides public Database provideDatabase(DatabaseImpl database)

    { return database; } @Provides public PrintStream providePrintStream() { return System.out; } } @Component(modules = MainModule.class) public interface MainComponent { DatabaseManager databaseManager(); }
  118. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  119. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  120. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  121. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  122. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  123. So far • Instantiation and its order automated • Caching

    • No boilerplate • No reflection • Verification at compile time • Scope • Great performance
  124. 2

  125. Reference • DIY: Build Your Own Dependency Injection Library ◦

    https://news.realm.io/news/android-pierre-yves-ricau-build-own-dependency-injection/ • Dagger ◦ https://google.github.io/dagger