Создайте определенный класс в графе объектов с помощью Guice

Я застрял в ситуации, когда заранее решил не создавать конкретный график с помощью Guice. Мне нужен завод, но я не могу понять, как его построить.

Чего я добился, так это системы управления игровыми объектами с учетом сеанса.

Все объекты, которые должны быть задействованы в этом, работают нормально.

Все они создаются с помощью инъекций, провайдеров, фабрик guice и т. д.

Единственный объект, которым мне действительно нужно управлять на этом уровне, — это Предметы.

Предметы также являются единственным объектом, который я не могу создать.

Элементы также имеют сложную иерархию классов, о которой клиент знает заранее, а код платформы — нет. В моем первоначальном проекте я построил свою собственную фабрику, чтобы иметь возможность использовать мои компоненты для правильного создания этих объектов.

До сих пор это работало нормально, поскольку эти объекты должны участвовать в уровне управления, мне нужно найти хитрое решение.

Вот текущая реализация:

abstract class Item{
  public Item(ItemID item){
    ...
  }
  ...
}

class MyItem extends Item{
   ...
}

class MyOtherItem extends MyItem{
   ...
}

class MyFavoriteItem extends Item{
   ...
}

Моя текущая реализация без guice выглядит примерно так

class ItemFactory{
   //this sequence generator is plugged into my persistance layer. Allows for generating
   //restful api calls for a specific item.
   @Inject
   private SequenceGenerator sequenceGenerator;

   public ItemID getNextItemID(){
     return sequenceGenerator.generateNextItemID();
   }

   //NOTE: these created objects do not participate in AOP
   //since they are not created by guice
   public <I extends Item> I createItem(Class<I> type){
     Item myItem = type.getConstructor(ItemID.class).newInstance(getNextItemID());
     return (I)myItem;
   }
}

Подтипы мне совершенно неизвестны и обычно предоставляются клиентским модулем. У меня есть несколько аннотаций, которые с любыми объектами, созданными с помощью guice, я могу обеспечить управляемое состояние в игровой среде, которую я разрабатываю.

Он отлично работает для всех объектов, кроме элемента... поскольку они не являются объектами, созданными вручную.

Я бы предпочел что-то вроде этого:

class MyItem extends Item{
  @Inject
  public MyItem(@Assisted ItemID itemID);
}

interface MyGuiceFactory{
  public <I extends Item> I createItem(Class<I> type, ItemID itemID);
}

class MyGuiceModule extends AbstractModule{
  public void configure(){
    install(new FactoryModuleBuilder().build(MyGuiceFactory.class));
  }
}

class MyGuiceApp{
  @Inject
  private MyGuiceFactory factory;

  private SequenceGenerator sequenceGenerator

  @Inject
  public MyGuiceApp(SequenceGenerator generator){
    sequenceGenerator = generator;
  }

  public ItemID getNextItemID(){
    return sequenceGenerator.generateNextSequenceID(ItemID.class);
  }

  public <I extends Item> I createItem(Class<I> type){
    return (I)factory.createItem(type, getNextItemID());
  }
}

Поскольку Guice не может использовать универсальный статический тип в качестве ключа, он не знает, что строить. Поскольку я не могу привязать его к чему-то конкретному или попросить его привязать к чему-то конкретному

Я застрял, не имея возможности построить его с помощью guice. Однако у меня есть код АОП, который нужно создать с помощью guice.

Если я могу создавать подтипы из своего приложения, эти подтипы могут участвовать в моем слое управляемого игрового состояния aop.

Любой совет будет большим подспорьем.

Любые советы по перефразировке вопроса также будут очень признательны.


person AnthonyJClink    schedule 08.04.2013    source источник
comment
Я не понимаю, почему ItemFactory имеет два метода. Как взаимодействуют ItemID и createItem?   -  person kan    schedule 08.04.2013
comment
Кроме того, предоставьте любые варианты использования, которых вы хотите достичь.   -  person kan    schedule 08.04.2013
comment
Я предоставил правки, надеюсь, это более понятно.   -  person AnthonyJClink    schedule 08.04.2013
comment
Литерал типа может быть тем, что мне нужно... Я просто не могу понять, куда его поместить?   -  person AnthonyJClink    schedule 08.04.2013
comment
Я не понимаю, зачем вам завод. Не могли бы вы показать код, который использует этот материал? Подозреваю, что вам просто нужно иметь Provider<MyItem> myItemProvider или Provider<MyOtherItem> myOtherItemProver впрыски вместо заводских.   -  person kan    schedule 08.04.2013
comment
С фабрикой мне не нужно знать подтип создаваемого элемента, и я могу передать параметры конструктору.   -  person AnthonyJClink    schedule 08.04.2013
comment
Проблема в том, что у меня есть N подтипов, и я не знаю многих из них заранее. Код, в котором я использую свою текущую фабрику без графических интерфейсов, находится по адресу github.com/AnthonyClink/Clinkworks-GameEngine/blob/master/   -  person AnthonyJClink    schedule 08.04.2013
comment
он используется здесь github.com/AnthonyClink/ Drugwars/blob/master/DrugWars/com/... Мне нужно, чтобы этот AK47 был создан Гайсом, а не мной. Если провайдер является решением, я не могу понять, как передать ему параметры.   -  person AnthonyJClink    schedule 08.04.2013
comment
Параметры типа передачи, я думаю, это то, о чем я спрашиваю. Даже с одним провайдером, как я могу .... дать то, что они хотят? предоставить элемент типа I extends Item   -  person AnthonyJClink    schedule 08.04.2013
comment
Я думаю, вам следует как-то избегать передачи .class на фабрику, например. у вас может быть карта фабрик или квалифицированные фабрики для каждого типа. Не могли бы вы дать более подробную информацию, чего вы пытаетесь достичь?   -  person kan    schedule 08.04.2013
comment
Мне просто нужен какой-то guice passthrough.   -  person AnthonyJClink    schedule 08.04.2013
comment
Я пытаюсь предоставить клиентам возможность создавать свои собственные типы элементов и управлять этими элементами с помощью объекта Game через StatManager и StatContainerInjectors.   -  person AnthonyJClink    schedule 08.04.2013
comment
Единственное, чего мне не хватает, — это возможности возвращать параметризованные экземпляры. //возможно, лучшее имя для этого.   -  person AnthonyJClink    schedule 08.04.2013
comment
Как я вижу, <I extends Item> I createItem(Class<I> itemType) эквивалентно Provider<ConcreteItem> provider, а затем provider.get(). Не могли бы вы показать пример того, как вы используете createItem? Как предоставляется Class?   -  person kan    schedule 08.04.2013
comment
@kan Я создаю GameManager, который является классом моего приложения GameManager manager = GameModule.getGameManager() Game game = gameManager.createGame(); Оружие расширяет элемент Weapon weapon = game.createItem(AK47.class //extends Weapon) все, что мне нужно, это результирующий объект game.createItem(Class<I> itemType), который будет создан с помощью guice. Я не могу найти явный способ сделать это. Итак, чтобы ответить на ваш вопрос, это клиентский код, который предоставляет тип элемента   -  person AnthonyJClink    schedule 08.04.2013
comment
@Kan Должен быть какой-то трюк с провайдером или решение для типового литерала, которое будет делать то же самое, что и параметризованный метод в игровом классе.   -  person AnthonyJClink    schedule 08.04.2013


Ответы (1)


Как видите, ваша игра сама по себе является доморощенным ioc-контейнером. Как я понимаю, где-то у вас есть

class AClass
{
  @Inject private Game game;
  void method() {
    Weapon weapon = game.createItem(AK47.class);
    weapon.shoot();
  }
}

что я имею в виду под использованием Provider:

class AClass
{ 
  @Inject private Provider<AK47> ak47Provider;
  void method() {
    Weapon weapon = ak47Provider.get();
    weapon.shoot();
  }
}

Когда вам просто нужно настроить модули инжектора для привязки всех провайдеров, которые могут быть у вас в приложении.

Тот же эффект вы могли бы получить, если бы внедрили Injector в игру и использовали его как фабрику объектов:

class GameBase
{
  @Inject private Injector injector;
  public <I extends Item> I createItem(Class<I> itemType){
    return injector.getInstance(itemType);
  }
}

Ты видишь, что у com.google.inject.Injector#getInstance точно такая же подпись, как у твоего createItem?

Но я предпочитаю первый вариант, он выглядит чище и меньше зависимостей.

person kan    schedule 08.04.2013
comment
Я догадываюсь, где я тогда застрял... Я не знаю, каким пакетом будет подтип, у меня нет реестра для них... так что во время связывания... мне нужно сделать что-то вроде for(eachPossibleSubtype : allPossibleClassesInClassHierarchy){ bind(eachPossibleSubtype).to(item.class)} ?. Мой игровой объект производит предметы по запросу пользователя. Это может быть совершенно новый модуль... если они добавят свои собственные типы предметов позже, я точно не смогу знать, что это такое... - person AnthonyJClink; 09.04.2013
comment
Я создаю своего рода студию по созданию игр. Единственный элемент, который я предоставляю, — это супертип ‹Item›. Совершенно новый проект под названием MyGameImplementation может создавать свои собственные подтипы, мне нужно, чтобы эти подтипы каким-то образом создавались с помощью guice и возвращались как общий тип переданного конкретного класса... Мне нужно создать его с помощью guice, чтобы я мог отслеживать количество... другие вещи, которые я даю бесплатно с моей библиотекой. передача инжектора кажется работоспособной, но мне не нравится идея, что инжектор создает что-то еще, кроме моего игрового менеджера. - person AnthonyJClink; 09.04.2013
comment
Подождите, я не нашел достаточно времени, чтобы прочитать то, что вы на самом деле написали. Можно ли с помощью провайдера дать ему знак чего-то вроде Provider‹? расширяет пункт›? - person AnthonyJClink; 09.04.2013
comment
seneario заключается в том, что, возможно, клиентский код создает поставщика, и они просто хотят передать несколько случайных классов предметов, может быть, список классов для создания в своем инвентаре владельцев магазинов... Или как в jpa вы делаете query.find( TypeToFind.класс) - person AnthonyJClink; 09.04.2013
comment
Вы ничего не знаете о подтипах Item, тогда это должны делать пользователи. Итак, просто позвольте добавить пользовательские модули guice в вашу систему. Вы можете просто предоставить список стандартных модулей и попросить пользователей создать инжектор, включая все необходимые модули, определяемые пользователем. Или вы можете создать своего рода арку плагинов, просканировав классы модулей, помеченные аннотацией, или используя java.util.ServiceLoader. Кроме того, вы можете попробовать заменить наследование композицией. Нет, Provider<?...> не имеет смысла. - person kan; 09.04.2013
comment
Я думаю, что где-то мне не хватает какой-то базовой фундаментальной концепции. Провайдеры всегда меня смущали, а мне нравятся классы с параметрами, поэтому я всегда использую модульный класс FactoryBuilder. - person AnthonyJClink; 09.04.2013
comment
Не хватает — вы ничего не знаете о подклассах предметов, но хотите сделать для него универсальную фабрику. Разрешить пользователям делать это так, как им нужно. - person kan; 09.04.2013
comment
Это правильное решение с обеих сторон. И поскольку ни один из ответов не соответствует API, который я имею в виду, необходимо изменить дизайн и придерживаться более бобовой модели с элементами. Спасибо за помощь в поиске правильного решения и за то, что вы так терпеливы со мной. - person AnthonyJClink; 09.04.2013