Static self referencing classes, a good idea or not?

Started by
5 comments, last by Telastyn 11 years, 5 months ago
This is a general OOP question, as I didn't know if this is an 'accepted' practice in programming!

I have some classes in my application that only ever get instantiated once - for example, a class that defines application settings and properties. However, when I want to reference this class instance from another class, I'm kinda stumped because I don't have a visible reference to my class instance.

Sure, I could pass the class instance reference into the functions that need it, but that seems ugly.

Instead, I've added a static reference to the class instance, and can therefore refer to that instance from any other class.

Example:

[source lang="java"]public class Settings
{
// static reference to a settings object
public static Settings ref;

public Settings()
{
// apply a self-reference
settings = self;
}

private void doSomething()
{
...
}
}[/source]

So, from another class file entirely, I can refer to my single Settings class instance by using the in-built static reference, giving me access to its private methods:

[source lang="java"]Settings.ref.doSomething();[/source]

Is this an acceptible method of doing this? Or is this type of self-referencing frowned upon? Should I just make all required 'public' members and methods in the class static instead?

[source lang="java"]public class Settings
{
public Settings()
{
// do nothing
}

public static void doSomething()
{
...
}
}[/source]

I'm looking forward to some insight on this!

Thanks all!
Advertisement
This has the problem of "lack of imagination". You might not have a reason to have more than one Settings object right now, but you might in the future. For instance, you may want to create a test where you check that two objects configured with different settings have the same behavior (say, one of the settings uses a naive algorithm and the other uses a fancy algorithm that should give the same results). If you hard-code the single instance in your code, you are closing the door to this possibility in the future.

Of course, using a global instance of the class, or making all the members static, all have the same problem.


The code I work with most days has a huge class of which only one instance can exist, and we have been living with it for years, although it's a mess and we have tons of examples of interesting things we could do if we could create more than one copy. The rest of the code (I am talking hundreds of thousands of lines of code) use this class all over the place.

Passing your Settings object around is not ugly: It's making a dependency explicit.
Thanks, I can see your point about it potentially closing the door to using further instances of the class for other reasons.

It might help to give some background on the class. It's a Canvas for a drawing / modelling application, so I know for a certainty that there can only ever be one instance of the class active at any time (this isn't a multiple-workspace type of project). A workspace can only have one canvas.

Perhaps I need to think about reorganising the communication of data between the classes outside of the workspace so that rather than relying on a call directly to a static method inside of the Canvas object, I can pass a reference to the (only) instance of the Canvas to the required classes as an argument.

It'll just mean a bunch of refactoring - but eh, if we had a few bucks everytime we did that... biggrin.png
I really don't like singletons, but there's a pattern I developed for a large scale project to overcome the lack of testabillty and the implementation coupling that the singletons usage brings :

[source lang="java"]public abstract class Settings {
private static final SingletonHolder <Settings> HOLDER = new SingletonHolder<Settings>("implementation.property");
public static final Settings getInstance() {
return HOLDER.getInstance();
}
public abstract void foo();
}

public class DefaultSettings extends Settings {
public void foo() {
// Do your thing
}
}

public class SingletonHolder <Type> {
private final <Type> instance;
public SingletonHolder(String property) {
this.instance = Class.forName(System.getProperty(property)).newInstance();
}
public Type getInstance() {
return instance;
}
}
[/source]

For the sake of brevity, I didn't write the exception handling code, and the SingletonHolder should be aware of changings on the value of the system property used to fetch the implementation's class name.
Yes, as has been stated (though I'll state it again to make it super clear), one of the biggest problems with global variables (which is what this is) is you get too many things dipping their fingers into stuff they really shouldn't be. Systems that really shouldn't be coupled grow complex dependencies on each other, all because the programmer didn't design the program well.

The argument that "you might need more than just one" is true, but I think it pales in comparison to the huge pain in the butt the complex, overly coupled system that grows from global variables. Debugging gets complicated (as changes to global variables are hidden by the fact they're buried deep in some code), and overall the design goes to crap as the global variable tumor begins to spread and more objects start referring to other objects that they really, really have no need to. At least they wouldn't have such a need if things were designed well.

And for what does need to be accessed and shared, thankfully we have parameters we can pass to function calls. This makes program control flow much easier to follow and much less error prone (because you, the programmer, may forget part A changes global variable B, which affects part C; passing a parameter makes this relationship and dependency explicit and hopefully you'll have less brain farts).
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Just pass the object's reference you need. And make up some "default behavior" if the reference turns out to be null (which could happen).

If the function that needs the reference is a method in some other object, you could make it so the object stores the reference. That way you can set it up in the constructor of said object or change it with a setter method later.

Besides, it gives you a good insight into your code when you think "Well, this object always used a single instance of this class... What happens if I switch it along the road? Is it safe? It crashes? It keeps working?"

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator


It's a Canvas for a drawing / modelling application, so I know for a certainty that there can only ever be one instance of the class active at any time (this isn't a multiple-workspace type of project). A workspace can only have one canvas.
[/quote]

You mean you don't have multiple canvases for layer effects? For undo/redo? For offscreen loading/saving? For multiple screens/multiple windows for model merging?

Having this sort of side effect in the constructor is decidedly undesirable even if you want a single common/default instance.

This topic is closed to new replies.

Advertisement