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

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

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

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

Benoît Quenaudon

August 04, 2017
Tweet

More Decks by Benoît Quenaudon

Other Decks in Programming

Transcript

  1. DI:依存性注入ライブラリを
    自分で作ろう
    Benoît Quenaudon @oldergod

    View full-size slide

  2. 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());
    }
    }

    View full-size slide

  3. 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);
    }
    }

    View full-size slide

  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();
    }

    View full-size slide

  5. public static void main(String... args) {
    ObjectGraph objectGraph = buildObjectGraph();
    VisitHandler visitHandler = objectGraph.get(VisitHandler.class);
    visitHandler.visit();
    }

    View full-size slide

  6. public class ObjectGraph {
    public T get(Class key) {
    throw new UnsupportedOperationException("Not implemented");
    }
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  14. public static void main(String... args) {
    ObjectGraph objectGraph = buildObjectGraph();
    VisitHandler visitHandler = objectGraph.get(VisitHandler.class);
    visitHandler.visit();
    }

    View full-size slide

  15. private static ObjectGraph buildObjectGraph() {
    Linker linker = new Linker();
    installFactories(linker);
    return new ObjectGraph(linker);
    }

    View full-size slide

  16. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, ...);
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  19. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    @Override
    public VisitHandler get(Linker linker) {
    Factory counterFactory = linker.factoryFor(Counter.class);
    Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory printStreamFactory = linker.factoryFor(PrintStream.class);
    PrintStream printStream = printStreamFactory.get(linker);
    return new Logger(printStreamFactory.get(linker));
    }
    });
    linker.install(PrintStream.class, new Factory() {

    View full-size slide

  20. Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory printStreamFactory = linker.factoryFor(PrintStream.class);
    PrintStream printStream = printStreamFactory.get(linker);
    return new Logger(printStreamFactory.get(linker));
    }
    });
    linker.install(PrintStream.class, new Factory() {
    @Override
    public PrintStream get(Linker linker) {
    return System.out;
    }
    });
    linker.install(Counter.class, new Factory() {

    View full-size slide

  21. Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory printStreamFactory = linker.factoryFor(PrintStream.class);
    PrintStream printStream = printStreamFactory.get(linker);
    return new Logger(printStreamFactory.get(linker));
    }
    });
    linker.install(PrintStream.class, new Factory() {
    @Override
    public PrintStream get(Linker linker) {
    return System.out;
    }
    });
    linker.install(Counter.class, new Factory() {

    View full-size slide

  22. Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory printStreamFactory = linker.factoryFor(PrintStream.class);
    PrintStream printStream = printStreamFactory.get(linker);
    return new Logger(printStreamFactory.get(linker));
    }
    });
    linker.install(PrintStream.class, new Factory() {
    @Override
    public PrintStream get(Linker linker) {
    return System.out;
    }
    });
    linker.install(Counter.class, new Factory() {

    View full-size slide

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

    View full-size slide

  24. linker.install(Logger.class, new Factory() {
    @Override
    public Logger get(Linker linker) {
    Factory 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() {
    @Override
    public Counter get(Linker linker) {
    return new Counter();
    }
    });
    }

    View full-size slide

  25. public class ValueFactory implements Factory {
    public static Factory 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;
    }
    }

    View full-size slide

  26. Logger logger = loggerFactory.get(linker);
    return new VisitHandler(counter, logger);
    }
    });
    linker.install(Logger.class, new Factory() {
    @Override
    public Logger get(Linker linker) {
    Factory 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() {
    @Override
    public Counter get(Linker linker) {
    return new Counter();
    }
    });
    }

    View full-size slide

  27. Logger logger = loggerFactory.get(linker);
    return new VisitHandler(counter, logger);
    }
    });
    linker.install(Logger.class, new Factory() {
    @Override
    public Logger get(Linker linker) {
    Factory 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() {
    @Override
    public Counter get(Linker linker) {
    return new Counter();
    }
    });
    }

    View full-size slide

  28. Logger logger = loggerFactory.get(linker);
    return new VisitHandler(counter, logger);
    }
    });
    linker.install(Logger.class, new Factory() {
    @Override
    public Logger get(Linker linker) {
    Factory 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() {
    @Override
    public Counter get(Linker linker) {
    return new Counter();
    }
    }));
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  31. Logger logger = loggerFactory.get(linker);
    return new VisitHandler(counter, logger);
    }
    });
    linker.install(Logger.class, new Factory() {
    @Override
    public Logger get(Linker linker) {
    Factory 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() {
    @Override
    public Counter get(Linker linker) {
    return new Counter();
    }
    }));
    }

    View full-size slide

  32. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    @Override
    public VisitHandler get(Linker linker) {
    Factory counterFactory = linker.factoryFor(Counter.class);
    Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory 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() {
    @Override
    public Counter get(Linker linker) {
    return new Counter();
    }
    }));
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  35. 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

    View full-size slide

  36. So far
    ● Instantiation and its order automated

    View full-size slide

  37. 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

    View full-size slide

  38. public interface Factory {
    T get(Linker linker);
    }

    View full-size slide

  39. public abstract class Factory {
    public void link(Linker linker) {
    }
    public abstract T get();
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  47. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    @Override
    public VisitHandler get(Linker linker) {
    Factory counterFactory = linker.factoryFor(Counter.class);
    Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory 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() {
    @Override
    public Counter get(Linker linker) {
    return new Counter();
    }
    }));
    }

    View full-size slide

  48. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    @Override
    public VisitHandler get(Linker linker) {
    Factory counterFactory = linker.factoryFor(Counter.class);
    Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory printStreamFactory = linker.factoryFor(PrintStream.class);
    PrintStream printStream = printStreamFactory.get(linker);
    return new Logger(printStream);
    }
    });
    linker.install(PrintStream.class, ValueFactory.of(System.out));

    View full-size slide

  49. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    Factory loggerFactory;
    Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory printStreamFactory = linker.factoryFor(PrintStream.class);
    PrintStream printStream = printStreamFactory.get(linker);

    View full-size slide

  50. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    Factory loggerFactory;
    Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory printStreamFactory = linker.factoryFor(PrintStream.class);
    PrintStream printStream = printStreamFactory.get(linker);

    View full-size slide

  51. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    Factory loggerFactory;
    Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory printStreamFactory = linker.factoryFor(PrintStream.class);
    PrintStream printStream = printStreamFactory.get(linker);

    View full-size slide

  52. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    Factory loggerFactory;
    Factory 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() {
    @Override
    public Logger get(Linker linker) {
    Factory printStreamFactory = linker.factoryFor(PrintStream.class);
    PrintStream printStream = printStreamFactory.get(linker);

    View full-size slide

  53. public class Linker {
    private final Map, Factory>> factories = new HashMap<>();
    private final Map, Factory>> linkedFactories = new HashMap<>();
    public void install(Class key, Factory factory) {
    factories.put(key, factory);
    }
    public Factory factoryFor(Class 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) factory;
    }
    }

    View full-size slide

  54. public class Linker {
    private final Map, Factory>> factories = new HashMap<>();
    private final Map, Factory>> linkedFactories = new HashMap<>();
    public void install(Class key, Factory factory) {
    factories.put(key, factory);
    }
    public Factory factoryFor(Class 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) factory;
    }
    }

    View full-size slide

  55. 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();
    }

    View full-size slide

  56. So far
    ● Instantiation and its order automated
    ● Caching

    View full-size slide

  57. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    Factory loggerFactory;
    Factory 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() {
    Factory 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() {
    @Override
    public Counter get() {
    return new Counter();
    }
    }));
    }

    View full-size slide

  58. 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());
    }
    }

    View full-size slide

  59. 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());
    }
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  63. private Factory> loadFactory(Class key) {
    Factory> factory = factories.get(key);
    if (factory != null) {
    return factory;
    }
    Constructor 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 Constructor findAtInjectConstructor(Class type) {
    for (Constructor> constructor : type.getConstructors()) {
    if (constructor.isAnnotationPresent(Inject.class)) {
    return (Constructor) constructor;
    }
    }
    return null;
    }

    View full-size slide

  64. private Factory> loadFactory(Class key) {
    Factory> factory = factories.get(key);
    if (factory != null) {
    return factory;
    }
    Constructor 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 Constructor findAtInjectConstructor(Class type) {
    for (Constructor> constructor : type.getConstructors()) {
    if (constructor.isAnnotationPresent(Inject.class)) {
    return (Constructor) constructor;
    }
    }
    return null;
    }

    View full-size slide

  65. private Factory> loadFactory(Class key) {
    Factory> factory = factories.get(key);
    if (factory != null) {
    return factory;
    }
    Constructor 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 Constructor findAtInjectConstructor(Class type) {
    for (Constructor> constructor : type.getConstructors()) {
    if (constructor.isAnnotationPresent(Inject.class)) {
    return (Constructor) constructor;
    }
    }
    return null;
    }

    View full-size slide

  66. private Factory> loadFactory(Class key) {
    Factory> factory = factories.get(key);
    if (factory != null) {
    return factory;
    }
    Constructor 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 Constructor findAtInjectConstructor(Class type) {
    for (Constructor> constructor : type.getConstructors()) {
    if (constructor.isAnnotationPresent(Inject.class)) {
    return (Constructor) constructor;
    }
    }
    return null;
    }

    View full-size slide

  67. private Factory> loadFactory(Class key) {
    Factory> factory = factories.get(key);
    if (factory != null) {
    return factory;
    }
    Constructor 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 Constructor findAtInjectConstructor(Class type) {
    for (Constructor> constructor : type.getConstructors()) {
    if (constructor.isAnnotationPresent(Inject.class)) {
    return (Constructor) constructor;
    }
    }
    return null;
    }

    View full-size slide

  68. private Factory> loadFactory(Class key) {
    Factory> factory = factories.get(key);
    if (factory != null) {
    return factory;
    }
    Constructor 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 Constructor findAtInjectConstructor(Class type) {
    for (Constructor> constructor : type.getConstructors()) {
    if (constructor.isAnnotationPresent(Inject.class)) {
    return (Constructor) constructor;
    }
    }
    return null;
    }

    View full-size slide

  69. private Factory> loadFactory(Class key) {
    Factory> factory = factories.get(key);
    if (factory != null) {
    return factory;
    }
    Constructor 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 Constructor findAtInjectConstructor(Class type) {
    for (Constructor> constructor : type.getConstructors()) {
    if (constructor.isAnnotationPresent(Inject.class)) {
    return (Constructor) constructor;
    }
    }
    return null;
    }

    View full-size slide

  70. public class ReflectiveFactory extends Factory {
    private final Constructor constructor;
    private final ArrayList> factories = new ArrayList<>();
    public ReflectiveFactory(Constructor 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);
    }
    }
    }

    View full-size slide

  71. public class ReflectiveFactory extends Factory {
    private final Constructor constructor;
    private final ArrayList> factories = new ArrayList<>();
    public ReflectiveFactory(Constructor 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);
    }
    }
    }

    View full-size slide

  72. public class ReflectiveFactory extends Factory {
    private final Constructor constructor;
    private final ArrayList> factories = new ArrayList<>();
    public ReflectiveFactory(Constructor 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);
    }
    }
    }

    View full-size slide

  73. public class ReflectiveFactory extends Factory {
    private final Constructor constructor;
    private final ArrayList> factories = new ArrayList<>();
    public ReflectiveFactory(Constructor 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);
    }
    }
    }

    View full-size slide

  74. public class ReflectiveFactory extends Factory {
    private final Constructor constructor;
    private final ArrayList> factories = new ArrayList<>();
    public ReflectiveFactory(Constructor 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);
    }
    }
    }

    View full-size slide

  75. 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() {}
    }

    View full-size slide

  76. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    Factory loggerFactory;
    Factory 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() {
    Factory 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() {
    @Override
    public Counter get() {
    return new Counter();
    }
    }));
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  80. private static void installFactories(Linker linker) {
    linker.install(PrintStream.class, ValueFactory.of(System.out));
    }

    View full-size slide

  81. private static void installFactories(Linker linker) {
    linker.install(VisitHandler.class, new Factory() {
    Factory loggerFactory;
    Factory 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() {
    Factory 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() {
    @Override
    public Counter get() {
    return new Counter();
    }
    }));
    }
    private static void installFactories(Linker linker) {
    linker.install(PrintStream.class, ValueFactory.of(System.out));
    }

    View full-size slide

  82. So far
    ● Instantiation and its order automated
    ● Caching
    ● No boilerplate

    View full-size slide

  83. linker.install(VisitHandler.class, new Factory() {
    Factory printStreamFactory;
    @Override
    public void link(Linker linker) {
    printStreamFactory = linker.factoryFor(PrintStream.class);
    }
    @Override
    public Logger get() {
    return new Logger(printStreamFactory.get());
    }
    });

    View full-size slide

  84. Annotation Processing

    View full-size slide

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

    View full-size slide

  86. public abstract class GeneratedFactory extends Factory {
    private final boolean singleton;
    public GeneratedFactory(boolean singleton) {
    this.singleton = singleton;
    }
    }
    public class Logger$$Factory extends GeneratedFactory {
    public Logger$$Factory() {
    super(false);
    }
    }

    View full-size slide

  87. private Factory> loadFactory(Class key) {
    Factory> factory = factories.get(key);
    if (factory != null) {
    return factory;
    }
    Constructor 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);
    }

    View full-size slide

  88. public class Linker {
    private Factory> loadFactory(Class 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);
    }
    }

    View full-size slide

  89. public class Linker {
    private Factory> loadFactory(Class 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);
    }
    }

    View full-size slide

  90. public abstract class GeneratedFactory extends Factory {
    public static Factory loadFactory(Class key) {
    String generatedClass = key.getName() + "$$Factory";
    try {
    Class> factoryClass =
    (Class>) Class.forName(generatedClass);
    GeneratedFactory 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;
    }
    }

    View full-size slide

  91. public abstract class GeneratedFactory extends Factory {
    public static Factory loadFactory(Class key) {
    String generatedClass = key.getName() + "$$Factory";
    try {
    Class> factoryClass =
    (Class>) Class.forName(generatedClass);
    GeneratedFactory 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;
    }
    }

    View full-size slide

  92. public abstract class GeneratedFactory extends Factory {
    public static Factory loadFactory(Class key) {
    String generatedClass = key.getName() + "$$Factory";
    try {
    Class> factoryClass =
    (Class>) Class.forName(generatedClass);
    GeneratedFactory 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;
    }
    }

    View full-size slide

  93. So far
    ● Instantiation and its order automated
    ● Caching
    ● No boilerplate
    ● No reflection

    View full-size slide

  94. 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);
    }
    }

    View full-size slide

  95. 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)

    View full-size slide

  96. 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 get(Class key) {
    Factory factory = linker.factoryFor(key);
    return factory.get();
    }
    public void validate(Class key) {
    linker.factoryFor(key);
    }
    }

    View full-size slide

  97. 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 get(Class key) {
    Factory factory = linker.factoryFor(key);
    return factory.get();
    }
    public void validate(Class key) {
    linker.factoryFor(key);
    }
    }

    View full-size slide

  98. static void installFactories(Linker linker) {
    linker.install(PrintStream.class, ValueFactory.of(System.out));
    }

    View full-size slide

  99. 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));
    }

    View full-size slide

  100. Annotation Processing

    View full-size slide

  101. 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));
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  105. 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));
    }

    View full-size slide

  106. private static ObjectGraph buildObjectGraph(List 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));
    }

    View full-size slide

  107. public static void main(String... args) {
    ObjectGraph objectGraph = buildObjectGraph();
    objectGraph.validate(DatabaseManager.class);
    // …
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  111. So far
    ● Instantiation and its order automated
    ● Caching
    ● No boilerplate
    ● No reflection
    ● Verification at compile time

    View full-size slide

  112. So far
    ● Instantiation and its order automated
    ● Caching
    ● No boilerplate
    ● No reflection
    ● Verification at compile time
    ● Scope?
    ● Great performance?
    ● Lazy computation?

    View full-size slide

  113. Fin
    Slides: goo.gl/nceQmc
    Benoît Quenaudon @oldergod

    View full-size slide

  114. 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

    View full-size slide