简体   繁体   中英

Guice - Inject object with two different implementations

First I have to say that I tried googling the answer to this question, but no answer explained my doubts. Anyway, What I'm trying to understand is the following:

public interface Animal{
 public void makeSound(int times);
}

This interface has two different implementations:

public class Cat implements Animal{
 @Override
 public void makeSound(int times){
   for(int=0;i<times;i++){ 
      this.meow();
   }
 }
}

public class Dog implements Animal{
 @Override
 public void makeSound(int times){
   for(int=0;i<times;i++){ 
      this.wolf();
   }
  }
}

I will be using those implementations as in the following example:

public class AnimalStateManager {

 @Inject
 private Animal animal;

 public void makeAnimalAct(){
   animal.makeSound(100)
 }

}

UPDATE 1.1 TO THE POST

And I have one more class using the same "Animal" interface:

 public class AnimalMakeSoundOnce {

     @Inject
     private Animal animal;

     public void makeSoundOnce(){
       animal.makeSound(1)
     }

    }

So my question would be: 1- How I can know what implementation is going to be injected to the AnimalStateManager? 2- What if I wanted to force the "animal" object on the "AnimalStateManager" to be a cat?

UPDATE 1.1 TO THE POST 3- What if I want to make the AnimalMakeSoundOnce uses the Dog implementation and the AnimalStateManager uses the Cat implementation?

Thanks in advance

In Guice you have to implement a module (override the AbstractModule class) and bind Animal to the specific implementation class. To answer your questions:

  1. You can of course call animal.getClass() to check at runtime which implementation class was injected. But this would break the prinziple of IOC where it does not matter which specific implementation you use.

  2. To force animal in your AnimalStateManager be cat you have to write your own Module.

     public class AnimalStateModule extends AbstractModule { @Override protected void configure() { bind(Animal.class).to(Cat.class); } } 

And to instantiate the AnimalState:

Injector inj = Guice.createInjector(new AnimalStateModule());
final AnimalStateManager ass = inj.getInstance(AnimalStateManager.class);
ass.makeAnimalAct(); // will cause a call to Cat.meow()

I think another important question is how you're going to be using both the MakeSound and MakeSoundOnce objects. Within the same module created above, there are a number of ways in order to specify which type you want, both of which are a method of binding annotations described ( https://github.com/google/guice/wiki/BindingAnnotations ):

1) You can use the @Named annotation provided by Guice. You'd have something that looks like the following:

@Override
protected void configure() {
    bind(Animal.class).annotatedWith(Names.named("Cat")).to(Cat.class);
    bind(Animal.class).annotatedWith(Names.named("Dog")).to(Dog.class);
}

which would then be used with:

@Inject @Named("Cat") private Animal animal;

within your *MakeSound classes.

2) You can also create your own annotation (described in the same link above with pretty good detail) which would give you the option to use:

@Inject @Cat private Animal animal;

within your *MakeSound classes. Most of the time we stick with the @Named annotation, due to it not requiring the extra Annotation interface to be created.

Will the *MakeSound classes be implementing by Injection? And will you ever need to switch the Dog/Cat implementations within the *MakeSound classes that you've described (ie. want to have a cat only meow once, and vice versa)?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM