It has been highlighted in the Beta Discussion forum by several users that the TV3D “global” objects, those who theoretically can’t have more than one instance, could be used without sharing the only instance in the whole application. This is the singleton design pattern, in which you can’t really construct a class instance explictely, but only fetch the current instance; if this instance is null, the class creates it internally and returns that instance.
Though instead of the private constructor & instance accessor technique, TV3D lets us use the constructor on the classes, but abstracts the actual inner instance that’s used in order to give us the right one.
It should be pointed out that singletons are considered an anti-pattern and should only be used if you are absolutely 100% certain that you only need a single instance of an object. In 99.9% of cases there is no reason to require a single instance of an object. Use of the singleton pattern is a controversial subject amongst developers and should only be used with the greatest of care as they can introduce issues, particularly with multi-threading. See this link for more information. If you feel the need to use global access to your objects, then you really should reconsider your design choices. If you don’t want to do that then consider that the singleton pattern is most often used as a global object reference and that if you really absolutely need a global, then use a global. At least then you won’t be stuck with only one instance.
Now that the doom and gloom is out of the way, feel free to continue at your own risk.
Here’s the list of classes that can be used as singletons, confirmed on December 16th 2006 by Sylvain (lead dev. of TV3D) :
TV3D does a ReleaseAll operation in the destructor of CTVEngine, so you can’t have more than one instance of it. It makes the application crash on random code, on seemingly random occassions...
Instanciate All TV3D Singleton Objects Wherever You Need Them.
Instead of sharing the instances in a shared/static/global class/module somewhere in your code, just create them (instanciate them!) in every code file you need to, or every package/namespace.
Here’s the procedure in several languages. I encourage everyone to add the language they used to implement it.
Note : All Modules could be Shared Classes instead (and then all Sub New and other methods should be Shared). Also I do realize that all “TV3DSingletons." prefixes are optional, but if you use Shared Classes you’re obliged to use them. Anyway it’s clearer about where the object comes from...
Module TV3DSingletons Private mScene As TVScene Private mGlobals As TVGlobals ' Etc. Sub New() mScene = New TVScene() mGlobals = New TVGlobals() ' Etc. End Sub ReadOnly Property Scene() As TVScene Get Return mScene End Get End Property ReadOnly Property Globals() As TVGlobals Get Return mGlobals End Get End Property ' Etc. End Module Module World Sub Render() TV3DSingletons.Scene.RenderAll(True) End Sub End Module Module GUI Private Mesh As TVMesh Sub Initialize() Mesh = TV3DSingletons.Scene.CreateBillboard(TV3DSingletons.Globals.GetTex("Foobar"), 0, 0, 0, 10, 10) End Sub End Module
Module World Private Scene As TVScene Sub New() Scene = New TVScene() End Sub Sub Render() Scene.RenderAll(True) End Sub End Module Module Gui Private Globals As TVGlobals Private Scene As TVScene Private Mesh As TVMesh Sub New() Globals = New TVGlobals() Scene = New TVScene() End Sub Sub Initialize() mMesh = Scene.CreateBillboard(Globals.GetTex("Foobar"), 0, 0, 0, 10, 10) End Sub End Module
static class TV3DSingletons { static TVScene scene; static TVGlobals globals; // Etc. static TV3DSingletons() { scene = new TVScene(); globals = new TVGlobals(); // Etc. } static TVScene Scene { get { return scene; } } static TVGlobals Globals { get { return globals; } } // Etc. } static class World { static void Render() { TV3DSingletons.Scene.RenderAll(true); } } static class Gui { static TVMesh mesh; static void Initialize() { mesh = TV3DSingletons.Scene.CreateBillboard(TV3DSingletons.Globals.GetTex("Foobar"), 0, 0, 0, 10, 10); } }
static class World { static TVScene scene; static World() { scene = new TVScene(); } static void Render() { scene.RenderAll(true); } } static class Gui { static TVScene scene; static TVGlobals globals; static TVMesh mesh; static World() { scene = new TVScene(); globals = new TVGlobals(); } static void Initialize() { mesh = scene.CreateBillboard(globals.GetTex("Foobar"), 0, 0, 0, 10, 10); } }
Some might wonder what’s so good about this pattern. Here’s a list of arguments in its favour :
Why let every codefile see TVGameControllers if they don’t use it?
’nuff said.
Since you don’t need to know the exterior world to use TV3D singletons, that allows completely independant code, modules, plug-ins or DLLs! If you plan on releasing the source or making a big project, it’s clearly an advantage for OOP consistency.