Я слышал бесчисленное количество раз о ловушках синглетонов / глобалов, и я понимаю, почему их так часто осуждают.
Чего я не понимаю, так это элегантной, не грязной альтернативы. Кажется, что альтернатива использованию Singletons / globals всегда включает пропускание объектов на миллион уровней вниз через объекты вашего движка, пока они не достигнут объектов, которые в них нуждаются.
Например, в моей игре я предварительно загружаю некоторые ресурсы при запуске игры. Эти активы не используются намного позже, когда игрок перемещается по главному меню и входит в игру. Должен ли я передавать эти данные из моего объекта Game, в мой объект ScreenManager (несмотря на тот факт, что только один экран действительно заботится об этих данных), затем в соответствующий объект Screen и где-либо еще?
Просто кажется, что я обмениваю данные о глобальном состоянии на беспорядочную инъекцию зависимостей, передавая данные объектам, которые даже не заботятся о данных, кроме как с целью передачи их дочерним объектам.
Это тот случай, когда синглтон будет хорошей вещью, или есть какое-то элегантное решение, которое мне не хватает?
источник
Если вы не можете / не можете иметь одну часть кода волшебным образом «знать» о некоторых данных, то это нужно будет как-то передать. Однако это не означает, что оно обязательно должно быть передано только через аргументы.
В вашем примере, не могли бы вы иметь какой-то «AssetManager», который бы загружал и сохранял активы, и тогда ScreenManager нужно было бы только дать ссылку на это (возможно, при создании)? В этом смысле вы передаете ссылки на ресурсы, заключенные в другой объект, и вы можете передать их один раз при инициализации, а не передавать их функции листьев, когда это требуется.
ИМХО, что AssetManager, будучи тем видом, который вам нужен только один, может быть синглтоном. При условии, что вы понимаете подводные камни и специально программируете их, чтобы избежать их (предположим, что синглтон будет доступен одновременно из нескольких потоков, и каждый раз вы будете ударять себя вилкой, когда вы делаете что-то, что нужно заблокировать), а затем выбивайте себя из строя.
источник
Я думаю, что Джейсон Д абсолютно прав - вот как я бы с этим справился:
В игре есть экземпляр AssetManager, объект, из которого вы можете получить любой актив по имени.
В игре:
В ScreenManager:
На экране:
Теперь все экраны имеют доступ к любым необходимым ресурсам. Это не сложнее и не безумнее, чем использование глобалов или синглетонов, и у вас есть возможность иметь 2 экземпляра Game, запущенных в одном приложении без столкновений. Когда-то мне нужно было сделать игру, состоящую из 8 мини-игр, которые использовали одни и те же базовые классы / рамки. Мне пришлось провести рефакторинг всех моих глобалов / синглетонов, чтобы использовать этот стиль передачи ссылок, и я никогда не оглядывался назад. Единственными вещами, которые должны быть глобальными, являются вещи, которые могут физически существовать только один раз, такие как аудио, сеть, ввод / вывод и т. Д.
источник
Вы можете использовать шаблон Factory для замены Singleton . Затем класс фабрики контролирует, сколько экземпляров вы можете создать, что вы можете легко изменить позже, когда обнаружите, что вам нужно более одного
AssetManager
. Как указано в этой статье :Другая, довольно ограниченная, возможность сделать класс статическим (что я не думаю, что это выполнимо для AssetManager и возможно только в языках, которые вообще имеют статические классы). Но это работает, только если вам не нужно наследование / полиморфизм. Это очень негибкое решение:
Речь идет о статических методах, но также может применяться к статическим классам.
источник