Guice - Внедрить объект с двумя разными реализациями - PullRequest
0 голосов
/ 04 марта 2019

Сначала я должен сказать, что пытался найти ответ на этот вопрос, но никакой ответ не объяснил мои сомнения.В любом случае, я пытаюсь понять следующее:

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

Этот интерфейс имеет две разные реализации:

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

Я буду использовать эти реализации, как в следующем примере:

public class AnimalStateManager {

 @Inject
 private Animal animal;

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

}

ОБНОВЛЕНИЕ 1.1 ДО ПОСТА

И у меня есть еще один класс, использующий тот же интерфейс "Animal":

 public class AnimalMakeSoundOnce {

     @Inject
     private Animal animal;

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

    }

Итакмой вопрос будет: 1- Как я могу узнать, какая реализация будет внедрена в AnimalStateManager?2- Что если я хотел бы заставить "animal" объект на "AnimalStateManager" быть котом?

ОБНОВЛЕНИЕ 1.1 ДО ПОСТА 3- Что если я хочу сделать AnimalMakeSoundOnceиспользует реализацию Dog, а AnimalStateManager использует реализацию Cat?

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Думаю, еще один важный вопрос - как вы собираетесь использовать объекты MakeSound и MakeSoundOnce.В том же модуле, созданном выше, есть несколько способов указать, какой тип вы хотите, оба из которых являются описанным методом привязки аннотаций (https://github.com/google/guice/wiki/BindingAnnotations):

1). Вы можете использовать @Namedаннотация предоставлена ​​Guice.У вас будет что-то похожее на следующее:

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

, которое затем будет использоваться с:

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

в ваших * классах MakeSound.

2)Вы также можете создать свою собственную аннотацию (описанную в той же ссылке выше с довольно хорошей детализацией), которая даст вам возможность использовать:

@Inject @Cat private Animal animal;

в ваших * классах MakeSound.Большую часть времени мы придерживаемся аннотации @Named, поскольку она не требует создания дополнительного интерфейса аннотации.

Будут ли классы * MakeSound реализовываться с помощью Injection?И нужно ли вам когда-нибудь переключать реализации Dog / Cat в классах * MakeSound, которые вы описали (т.е. хотите, чтобы кошка только мяукала один раз, и наоборот)?

0 голосов
/ 04 марта 2019

В Guice вы должны реализовать модуль (переопределить класс AbstractModule) и связать Animal с конкретным классом реализации.Чтобы ответить на ваши вопросы:

  1. Конечно, вы можете позвонить animal.getClass(), чтобы проверить во время выполнения, какой класс реализации был введен.Но это нарушит принцип IOC, где не имеет значения, какую конкретную реализацию вы используете.

  2. Чтобы заставить animal в вашем AnimalStateManager быть котом, вы должны написать свой собственный модуль..

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

И для создания экземпляра AnimalState:

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