public class Request { public String parameter; public int argument; }  public abstract class Worker{ protected final int argument; public Worker(int argument) { this.argument = argument; } public abstract void doWork(); }  public class Worker1 extends Worker { private ServiceA serviceA; private ServiceB serviceB; public Worker1(ServiceA serviceA, ServiceB serviceB, int argument) { super(argument); this.serviceA = serviceA; this.serviceB = serviceB; } @Override public void doWork() { System.out.println(String.format("Worker1 starts work with argument %d services %s and %s", argument, serviceA, serviceB)); } } public class Worker2 extends Worker { private ServiceB serviceB; private ServiceC serviceC; public Worker2(ServiceB serviceB, ServiceC serviceC, int argument) { super(argument); this.serviceB = serviceB; this.serviceC = serviceC; } @Override public void doWork() { System.out.println(String.format("Worker2 starts work with argument %d services %s and %s", argument, serviceB, serviceC)); } }  public class RequestHandler { private final ServiceA serviceA; private final ServiceB serviceB; private final ServiceC serviceC; public RequestHandler(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC) { this.serviceA = serviceA; this.serviceB = serviceB; this.serviceC = serviceC; } public void handleRequest(Request request) { Worker worker = null; if (request.parameter.equals("case1")) { worker = new Worker1(request.argument); } else if (request.parameter.equals("case2")) { worker = new Worker2(request.argument); } //          //,     worker.setServiceA(serviceA); worker.setServiceB(serviceB); worker.setServiceC(serviceC); worker.doWork(); } }  <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>${guice.version}</version> </dependency>  public abstract class Worker { public abstract void doWork(); }  public class Worker1 extends Worker{ private ServiceA serviceA; private ServiceB serviceB; @Inject public Worker1(ServiceA serviceA, ServiceB serviceB) { this.serviceA = serviceA; this.serviceB = serviceB; } @Override public void doWork() { System.out.println(String.format("Worker1 starts work with %s and %s", serviceA, serviceB)); } }  @Singleton public class RequestHandler { private Provider<Worker1> worker1Provider; private Provider<Worker2> worker2Provider; @Inject public RequestHandler(Provider<Worker1> worker1Provider, Provider<Worker2> worker2Provider) { this.worker1Provider = worker1Provider; this.worker2Provider = worker2Provider; } public void handleRequest(Request request) { Worker worker = null; if (request.parameter.equals("case1")) { worker = worker1Provider.get(); } else if (request.parameter.equals("case2")) { worker = worker2Provider.get(); } worker.doWork(); } } Provider <T> - an object capable of providing instances of type TIn this case, the Provider is a factory provided by the Guice framework. After a dependency is obtained on a provider typed by the Worker class, each time the
.get() method is .get() we get a new instance of the Worker class (unless, of course, the Worker is declared as a Singleton ).  public static void main( String[] args ) { Request request = new Request(); request.parameter = "case1"; request.argument = 5; Injector injector = Guice.createInjector(); RequestHandler requestHandler = injector.getInstance(RequestHandler.class); requestHandler.handleRequest(request); request.parameter = "case2"; requestHandler.handleRequest(request); }  @Inject public Worker1(ServiceA serviceA, ServiceB serviceB, int argument) {  @Singleton public class WorkerFactory { private ServiceA serviceA; private ServiceB serviceB; private ServiceC serviceC; @Inject public WorkerFactory(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC) { this.serviceA = serviceA; this.serviceB = serviceB; this.serviceC = serviceC; } public Worker1 createWorker1 (int argument) { return new Worker1(serviceA, serviceB, argument); } public Worker2 createWorker2 (int argument) { return new Worker2(serviceB, serviceC, argument); } }  <dependency> <groupId>com.google.inject.extensions</groupId> <artifactId>guice-assistedinject</artifactId> <version>${guice.version}</version> </dependency>  public interface WorkerFactory { Worker1 createWorker1 (int argument); Worker2 createWorker2 (int argument); }  public class Module extends AbstractModule { @Override protected void configure() { install(new FactoryModuleBuilder().implement(Worker1.class, Worker1.class) .implement(Worker2.class, Worker2.class) .build(WorkerFactory.class)); } } FactoryModuleBuilder - provides a number of construct objects.We have the opportunity to combine user options with objects provided by Guice .
build(WorkerFactory.class) method build(WorkerFactory.class) tells Guice to provide an implementation of the WorkerFactory factory; implement (Class<T> source, Class<? extends T> target) source - the return value interface, target - its implementation, which our factory will provide;install(new FactoryModuleBuilder()) - we complete the configuration by adding a new module to ours. @AssistedInject public Worker1(ServiceA serviceA, ServiceB serviceB, @Assisted int argument)  @Singleton public class RequestHandler { private WorkerFactory workerFactory; @Inject public RequestHandler(WorkerFactory workerFactory) { this.workerFactory = workerFactory; } public void handleRequest(Request request) { Worker worker = null; if (request.parameter.equals("case1")) { worker = workerFactory.createWorker1(request.argument); } else if (request.parameter.equals("case2")) { worker = workerFactory.createWorker2(request.argument); } worker.doWork(); } }   Injector injector = Guice.createInjector(new Module());  public interface WorkerFactory<T extends Worker> { T createWorker (int argument); }  public class Module extends AbstractModule{ @Override protected void configure() { install(new FactoryModuleBuilder().implement(Worker.class, Worker1.class) .build(new TypeLiteral<WorkerFactory<Worker1>>() {})); install(new FactoryModuleBuilder().implement(Worker.class, Worker2.class) .build(new TypeLiteral<WorkerFactory<Worker2>>() {})); } } TypeLiteral <T> - represents a generic type of T. Java doesn’tThus, since Java has no idea of ​​a parameterized class, Guice created its own.
 @Singleton public class RequestHandler { private WorkerFactory<Worker1> worker1Factory; private WorkerFactory<Worker2> worker2Factory; @Inject public RequestHandler(WorkerFactory<Worker1> worker1Factory, WorkerFactory<Worker2> worker2Factory) { this.worker1Factory = worker1Factory; this.worker2Factory = worker2Factory; } public void handleRequest(Request request) { Worker worker = null; if (request.parameter.equals("case1")) { worker = worker1Factory.createWorker(request.argument); } else if (request.parameter.equals("case2")) { worker = worker2Factory.createWorker(request.argument); } worker.doWork(); } } WorkerFactory<WorkerN> workerNFactory every time in WorkerFactory<WorkerN> workerNFactory . Now let's fix this using the multibindings extension. In particular, we will use MapBinder :MapBinder - an API for bind multiple maps.MapBinder allows you to collect all the dependencies together in one map, and then inject it all at once.
 <dependency> <groupId>com.google.inject.extensions</groupId> <artifactId>guice-multibindings</artifactId> <version>4.2.0</version> </dependency>  MapBinder<String, WorkerFactory> binder = MapBinder.newMapBinder(binder(), String.class, WorkerFactory.class);   new TypeLiteral<WorkerFactory<Worker1>>(){} addBinding() and to() methods. Note the presence of an overloaded version of the method that accepts TypeLiteral . This is how the module will look like: public class Module extends AbstractModule{ @Override protected void configure() { install(new FactoryModuleBuilder().implement(Worker.class, Worker1.class) .build(new TypeLiteral<WorkerFactory<Worker1>>() {})); install(new FactoryModuleBuilder().implement(Worker.class, Worker2.class) .build(new TypeLiteral<WorkerFactory<Worker2>>() {})); MapBinder<String, WorkerFactory> binder = MapBinder.newMapBinder(binder(), String.class, WorkerFactory.class); binder.addBinding("case1").to(new TypeLiteral<WorkerFactory<Worker1>>(){}); binder.addBinding("case2").to(new TypeLiteral<WorkerFactory<Worker2>>(){}); } }  @Singleton public class RequestHandler { private Map<String, WorkerFactory> workerFactoryMap; @Inject public RequestHandler(Map<String, WorkerFactory> workerFactoryMap) { this.workerFactoryMap = workerFactoryMap; } public void handleRequest(Request request) { Worker worker = workerFactoryMap.get(request.parameter) .createWorker(request.argument); worker.doWork(); } } get() method.Source: https://habr.com/ru/post/358278/
All Articles