What is a possible alternative to these static variables?

I created a simple graphics engine that I plan to use in the game. The problem I am facing is understanding how the instance of the class, to which several frames of the stack will be available, is not static (people made it clear that static variables are just evil).

I have an example code below:

class MyGame { class InputEngine { internal void DoInput() { if (Keys["F1"].IsPressed) { // Create a window using the gui engine } } } class GuiEngine { internal void Update() { } internal void Draw() { } } private GuiEngine engine; private InputEngine input; internal MyGame() { this.input = new InputEngine(); this.engine = new GuiEngine(); } internal void Update() { this.engine.Update(); this.input.DoInput(); } internal void Draw() { this.engine.Draw(); } } 

How can I access a gui engine instance not only from an input example, but from dozens of other places without making it static. (I would rather not pass it as a parameter).

+4
source share
9 answers

You have only three real options for passing -

  • Statics
  • Parameterization (method, method, etc.)
  • Delegates / Shutters / Lambda

Techniques such as inverting control containers can also help in creating, managing lifetimes and locating instances. Add to the dependency and the entire life cycle can be automatic with minimal attribution / coding.

Of the three methods, statics and parameterization pass the β€œtest” software best in terms of obviousness and simplicity. IoC is quite readable. However, DI code bases tend to be more like black magic with implicit behavior for life, location, and binding.

Delegates, closing, etc. may work very well, preserving the context at creation, but debugging can be a bit of a nightmare, and often saving / reading the closing code seems messy, as it is rarely performed in the context of where it is written.

Statics, as you indicate, is probably the most rude, harder to taunt, replace, etc.

+1
source

Solving your problem may be a redesign. Something is wrong when you need

access to the gui engine instance not only from the input example, but also from dozens of other places

This indicates a lot of dependencies, which may just be wrong.

+2
source

An injection of addiction is your friend. As already mentioned, expose the dependency through the constructor (which seems to be a typical way), or you can do it through Property injection. Anyway, when you register your dependency on application launch, you can tell the container to make it a single, so when you request a link, you get the same effect as a static link.

For Ninject, the syntax is:

 var kernel = new Ninject.StandardKernel(settings); kernel.Bind<ISomeInterface>().To<MyConcreteObject>().InSingletonScope(); 

For Unity, the syntax is:

 UnityContainer container = new UnityContainer(); container.RegisterType<ISomeInterface, MyConcreteObject>(new ContainerControlledLifetimeManager()); 

So your classes might be something like this:

 public class MyThing { ISomeInterface _mySingletonObject; public MyThing(ISomeInterface mySingletonObject) { _mySingletonObject = mySingletonObject; } } 

This class will always have the same instance of the object into which it was entered if you use a container to resolve an instance of this class.

Again, for Ninject:

 var singletopnObject = kernel.Get<ISomeInterface>(); 

And unity (I think from memory)

 var singletopnObject = container.Resolve<ISomeInterface>(); 

And all other IoC containers offer the same features in different ways.

PS Statics are not evil. They are fast and very useful when used properly.

+2
source

Perhaps you could implement a singleton pattern in your type of game engine? If you never create more than one instance of an object, I think this is the perfect choice.

Otherwise, you can try using IoC , for example, Mincrosoft Unity .

+1
source

Pass the Game instance to the constructor of the other classes and save it in a local variable. Thus, you can access the Game and all your members from almost anywhere, but you can still have multiple instances of the game.

You can automate this using Injection Dependency.

In some situations, thread-static variables are an alternative, but I don't think yours is one of them.

0
source

You can use the IoC framework and use dependency injection to have the input mechanism where you need it. Alternatively, you can use the locator pattern.

0
source

This method is called dependency injection. In fact, you inject the "static variable" into the instance. As for the instance, this is a regular instance variable. You just pass your gui instance to the constructor.

0
source

You can pass it as a constructor parameter, not a method parameter, for example:

 public class InputEngine { public InputEngine(IGuiEngine guiEngine) { // set private member to store guiEngine } } 

Note. I also changed GuiEngine to an interface - this way you can use the Injection Dependency container, such as StructureMap , to automatically transfer the GUI engine to your instances as needed. Helps with testing.

Alternatively, you can use the DI container or the factory class to provide one instance of the GUI Engine.

0
source

Now the first thing regarding statics is IMHO, not that a static function, single classes themselves are evil. But if you want to create some automated tests for classes that use your static context, that would be practically impossible.

So, if you want to completely ignore any hope of creating automated tests, then go ahead, make the class static with static data.

If you want this option to be open, I would suggest you look at things like IOC containers ( structuremap , which is my favorite). You may have a static IOC container (ahem) that you use to instantiate your dependencies. Dependencies take an instance, for example, GuiEngine, as a constructor argument. And your IOC container will ensure that all dependencies get the same instance, assuming you configured it correctly.

As Tim points out, extracting an interface for your engine classes would be a good idea, as it would allow you to create alternative implementations for the specified tests, for example. layout, stub, spy, dummy objects, etc.

0
source

Source: https://habr.com/ru/post/1336664/


All Articles