- Home /
Can someone help me understand the Toolbox Pattern (wiki)
Hi all, I've been looking at this Toolbox pattern on the wiki http://wiki.unity3d.com/index.php/Toolbox
Very interesting approach, but there's one thing I don't understand:
In MyClass, the author creates a public class MyComponent
[System.Serializable]
public class MyComponent {
public string anotherGlobalVar = "yeah";
}
Which he then adds as a component via RegisterComponent method
MyComponent myComponent = Toolbox.Instance.RegisterComponent<MyComponent>();
But there's one thing that doesn't make sense to me: RegisterComponent signature is supposed to take a Component.
static public T RegisterComponent<T> () where T: Component
How on earth could the compiler accept that we use a MyComponent (which is just a standard class not derived from any other) as a Component?
I tried this in Unity and it gave me a compile error by the way.
The type MyComponent must be convertible to UnityEngine.Component in order to use it ...
So either I'm missing something in the big picture, or the example in the wiki is wrong.
Answer by Bonfire-Boy · Oct 14, 2016 at 09:02 AM
You're right, that code is broken.
But the thing to understand is that the MyComponent class is only there as a kind of placeholder to show you the usage of the other stuff.
Just making it a subclass of Component would fix it the compiler error (note: don't do this, continue reading!).
[System.Serializable]
public class MyComponent : UnityEngine.Component
{
public string anotherGlobalVar = "yeah";
}
In practice though, the idea is that MyComponent is a MonoBehaviour. If it is , then it will also compile because MonoBehaviour derives from Component.
So you don't actually want to use the MyComponent bit of that code at all. Just use one of your own MonoBehaviours in the place where they use the MyComponent class.
The page really doesn't explain it well.
Personal opinion: for me this is all a bit over-the-top. In Unity I use a lot of singleton MonoBehaviours, of various types (eg with scene or application lifetimes, created in the inspector or at runtime, whether from prefabs or not, and so on). They can simplify ones code massively, the benefits of which can outweigh other considerations. Some people go on about them being awful code design but really, you just have to be careful. I've been using singletons for over 30 years and literally never had a major issue caused by it.
[Edit: this opinion-piece was based on my own misunderstanding of the nature of the ToolBox and its intention! Hopefully this is clarified in discussion of Joshua's other answer, below)]
thanks a lot I had come to the same conclusion as you. I also love to use singletons, the main thing is to have them be monobehaviours so they're destroyed when the scene unloads. Standard C# singletons are disliked because you have to explicitly destroy them, which is not the case for monobehaviours
You're welcome. Sorry to have to introduce some negativity to this but I'm afraid I don't actually agree with very much of your comment.
the main thing is to have them be monobehaviours so they're destroyed when the scene unloads.
No, they certainly do not have to be $$anonymous$$onoBehaviours. I would say that (like any class) if they're not utilising the game loop in some way it's probably better for them not to be.
And the ones that are $$anonymous$$onoBehaviours absolutely do not need to be destroyed when the scene unloads (only the ones that you want to be destroyed then need to be). Look at what I wrote in my answer about the variety of types of singleton - they can have application lifetimes (using DontDestroyOnLoad). I use that pattern rather more than the scene lifetime one. For example, one often wants a $$anonymous$$anager type of class to persist throughout the application rather than have to recreate it in every scene.
Standard C# singletons are disliked because you have to explicitly destroy them, which is not the case for monobehaviours
There's a lot more to why some people call singletons "evil" than that. in fact I would say that that reason is way down the list. It's worth researching, in order to help one avoid the pitfalls. The singleton-haters do have a point (well, quite a few points actually).
And as I think should be clear now, there is no such thing as a "standard singleton" (especially not in the Unity context).
Answer by JoshuaMcKenzie · Oct 14, 2016 at 05:45 PM
@jeango To be frank that's just the Singleton Pattern. It doesn't do anything differently that singletons do, and is also vulnerable to the same issues that plague Singletons.
By their very nature, Singletons invite tight coupling due to implementing to a concrete class. By definition they use statics and you can't abstract away statics easily (though its possible with some clever use of Extension Methods). Singletons also cause a slew of headaches with Unit Testing, multi-threading, and really its just a fancy word for storing a global state, all of which are (or can be) bad.
Thats not to say that you shouldn't ever use singletons, on smaller projects they'll work just fine. but singletons are like minefields, you need tread around them carefully, which is easy on small projects. When you get to huge projects that involves a larger team Singletons are just not the answer (like pushing a parade through a minefield instead of a party of 5, things are far more likely to blow up).
At that point Dependency Injection (DI) is the way to go. Then you don't make classes singletons, you make them single instances that are manually passed to the classes that need them (preferably via a multitude of interfaces). Since these single instance classes are no longer Singletons they don't need a static reference for themselves anymore and thus no longer manage their lifetime anymore. instead you would have a factory (enter Factory Design Pattern) handle that. The factories don't need any static reference to the "mock singletons",but they can just hold an internal reference and if the instance is null they make one, otherwise they pass back the pre-exisiting instance. The factory themselves can also be abstracted behind an interface.
By using DI it makes every class's job easier as they have no idea which concrete class the data they want is from (making them Decoupled) plus since that data is "pushed" to the classes that need them, (those classes no longer try to "pull" them from some global state), it becomes significantly easier to mock that data (great for unit testing). the classes using the data no longer need to know that the data is from some singleton nor need to understand the lifetime state of said classes. They can just focus on their specific use-cases
It does something similar and may have some similar issues but unless I'm missing something, using that Toolbox is significantly different to making a class into a Singleton.
1) it gives you a way of creating and accessing unique instances of any Component-derived class,
2) but they're only unique within the ToolBox. It does not prevent you from creating other instances of those classes outside of the ToolBox. In fact you could even remove the ToolBox's Singleton-ness with little impact except upon the way you access the ToolBox instance(s), and thus have multiple ToolBoxes, which could be quite a useful pattern.
Anyway, interesting stuff but does not address the question in any way. $$anonymous$$aybe this should be a reply to my comment rather than an answer to the question?
[Edit: to be fair I just realised that it does address the question's title, if not its content]
Toolbox IS the singleton, it inherits from the Singleton class.
1) Thats better done with a Factory, not a singleton.
2) On the contrary any and every class that is referencing ToolBox will have to change. The goal should always be to design and implement to an abstraction, not concretions. Toolbox is a Concrete class. Any class that uses "ToolBox.Instance" is hard coupled to the ToolBox class so if you "remove that Singleton-ness" it'll in fact have a huge impact. if you have hundreds of classes referencing ToolBox, you'll have to also update hundreds of classes anytime you change ToolBox.
Try and answer these questions. How can you Access the data Toolbox has without using the keyword "Toolbox" in any class? How can you access them without using statics? with the current implementation you can't. you're forced to code very specific classes that must always use Toolbox.
Singletons are great for beginners and on smaller projects. they are relatively quick to write up and all the code is in one place for a beginning programmer to understand. but as you try to write more code that wants to be more dynamic at runtime or change in specific scenarios... you'll quickly feel its limitations.
Because of this I felt this may be an XY problem (Asker has a problem but asks the wrong question, and thus gets the right answer to the question asked but not the answer they actually needed), and thus felt it prudent to show the dangers to blindly using singletons.
I stand by everything I've said, it comes from decades of direct experience, including huge projects. I actually agree with most of what you've written too. It's clear to me from your questions that we're talking at cross-purposes here.
Anyway, this isn't the right place for this. Sorry for opening a can of worms.
Really, the only reason I added that "Personal Opinion" bit to my answer was because the purpose of my answer was to explain the compilation issues and the intention of that ToolBox class to the OP (that's what they were asking about).
But I didn't want my doing so to appear to be advocating the use of that particular ToolBox class. I think that lack of support is something we can agree on, even if we have different reasons for it.
Answer by jeango · Oct 14, 2016 at 08:32 PM
thank you both for your involvement in answering my question. I don't mind at all that this little debate has occurred there are a lot of things for me to learn from all you guys are saying. and hopefully some other people will benefit from it