Closed YimingIsCOLD closed 6 years ago
I think there is no BEST way in this case. Only preferable way you like.
I know which one I'd recommend ;-)
Hey, here's my 2c.
Singleton. Yep, it's singleton, we all know this one all too well :) Not testable, poor maintainability and modularity. In particular: it's not easy do IMyService and then swap implementations with singletons, which can be really useful.
Kind of reminds me of the service locator antipattern. Much better than singleton, but still has issues. What if service A depends on B and B depends on C? You have to manually construct the objects in the correct order. Small change ( B no longer depends on C but on D) can result in need to rewrite stuff. Rewriting stuff -> potentially introducing bugs.
This is what we do and IMO Entitas works sweet with Zenject. You don't need to worry on the correct order of initializing things - Zenject keeps track of the dependency graph and constructs everything in the correct order.
This is how we glue Entitas and Zenject together. You need an InjectableFeature:
https://gist.github.com/kdrzymala/23d37c745377957cf9e63aeb55ceb6b5
Then in your GameController you do:
[Inject]
DiContainer _container;
[Inject]
Contexts _contexts;
void Start()
{
_systems = new InjectableFeature( "Root system" );
CreateSystems( _contexts ); // all your _systems.Add(new ASystem); goes here
_systems.IncjectSelfAndChildren( _container );
_systems.Initialize();
}
And that's it. Magic can now happen :) You can use [Inject] in your systems now. We abstract quite a few things that way: saving (we have a couple strategies that can be swapped), logging, analytcs (mutliple providers), ads (same as analytics), object pooling, etc.
Also - you no longer need to use Contexts.sharedinstance (which is a singleton) - you can inject Contexts into your MonoBehaviours (this is where you'd normally use Contexts.sharedinstance).
Zenject and Entitas are the top 2 awesome things happened to me in the past 2-3 years :) Together they help to create loosely coupled, testable and maintainable code.
@kdrzymala I like your solution very much. Just one thing that I don't understand fully: how would a unit test for a reactive system look a like with zenject where I need to substitute a service?
@StormRene This where DI frameworks shine ;-) TL;DR; you just do different bindings for tests.
Zenject docs have a bit more to say about it. I'll just guide you there, as there's no point of repeating this stuff: https://github.com/modesttree/Zenject/blob/master/Documentation/WritingAutomatedTests.md https://github.com/modesttree/Zenject/blob/master/Documentation/AutoMocking.md
(seriously, Zenject has awesome documentation)
@kdrzymala Pretty cool! Thanks for the links.
@kdrzymala Zenject is really interesting. I shall give it a try. Thanks for sharing.
Should we have a small dependencies injection framework built into Entitas?
@YimingIsCOLD IMO Zenject works great and is opensource, so I'd say that there's no point in re-inwenting the wheel. Only downside is (if it matters to you) that it has dependencies to UnityEngine. If that's an issue you could try Ninject - which is quite similar.
@kdrzymala There is also a version that works unity-independent on the release page Zenject-NonUnity.v5.5.1.zip .
@kdrzymala Okay. Zenject documentation is really awesome and with the code snippet you shared, I had already setup and started using Zenject.
Hi,
What is the best way to pass services into an Entitas systems? There is a discussion in #609 with some pros and cons that @sschmid have point out but still could not decide on what ways to do it.
Singleton, like match-one example
Using a meta context to pass registered service to system. Just like the
Game Architecture With Entitas
in the wiki tutorial made by @FNGGamesUse dependencies injection technique like Zenject.
Cheers