Singletons

I think the takeaway is that singletons can be useful but that have some pretty serious downsides. When you’re programming on your own and are re-writing or not caring about re-usability, the problems with singletons usually do not outweigh the benefits so you can use them. But if you join a big project with 20+ people working on it, a singleton might cause problems down the road for someone else, in which case you best avoid their use.

If you program for a learning point of view, to understand what works and what doesn’t (including the problems of what works now vs. what will keep working as I design more of my game), I would recommend trying to solve your problem without singletons just so that you know other solutions for situations where you can’t fall back onto singletons.

But if you want to make something fun that works now, do what is easiest and understand that you might have to change things later. It’s all about when you choose to pay the price, and how time affects that price.

Thanks for all the input. Although, I don’t think I’ll make classes for each skill…seems a bit overkill to me.

The singleton is working for what I’m doing, and efficiency only matters if it works, but doesn’t work fast enough. I don’t need more than one instance of the class either, it’s simply going to load some stats if the game is being loaded, or make some. Simple enough. They aren’t referenced enough to even deserve their own individual classes, except for the player name of course, but still. I think it’ll be fine, if I have problems, luckily, it’s all written/organized code, and modifying it will never be a problem :slight_smile:

I apologize again for being so touchy, it was a bad day. I’m sure we all have those. lol.

(Oh, and I didn’t read the “tome” on asking good questions. I’ll just make sure to be more specific and clear if that’s okay ;))

This discussion did veer off path into Singletons and I’ll accept some of the blame for that.

In your original post you said that the singleton wasn’t working and in your most recent post you’re now saying it is.

What did you end up changing and what aspect of the Slick library restricted what you were trying to do? Can you point us towards the API calls that were causing trouble?

If it’s a tiny game, then I agree. If it’s something that you will be working on for a few months, and will be measured in 10s of thousands of lines of code, then it helps to follow good guide lines.

I have tonnes of bugs in my code, which have been caused simply because I have changed something else where. Good practices can help to isolate potential issues, and make them more durable to change. It also helps to avoid that “oh, f*ck” moment when you realise you need to build something that doesn’t fit into the current system.

Unit tests are great for avoiding “breakage at a distance”, or at least catching it very early. I just can’t recommend them enough as part of writing any robust codebase.

I hardly ever reach 10,000 LOC though: when I get near that point, I end up writing some abstraction or finding some library already written that lets me cut out huge chunks of my code and bring the LOC back down. I suppose it’s because I write most of my stuff in languages that don’t require boilerplate (perl+Moose, python, scala), so things like getters/setters simply don’t appear in the codebase.

Go go operator overloading! The lack of is the real problem here.

To point that out. I do have an understanding for most langauge features, so mostly use Interfaces for a lot of things. Why? Because errors when changing a Interface diretly appear in my super nice IDE. I add the methods and stuff und voila. I never had the problem that I changed something and generated tons of Bugs Oo Sounds like there is something broken und your system in general…
To be honest I’m just a anti-Clean-Code dude :smiley: I can’ split my method into 5 sub-methos which are private because a book says it’s cleaner.

Nothing with slick was wrong, it was actually just something that messing up the singleton externally. In which this was my own fault, and I assumed it my singleton was broken, as I’ve never used one before.

then, how about singleton use in handling sprite to save memory?

Singleton for sprites probably isn’t the best pattern, especially since that would imply either one class that has access to all of the images or that you only need one simple set of images for the entirety of the game. Neither options sounds good to me.

Another option would be to use the somewhat similar ‘Flyweight Pattern’. Which, in basic terms (And basically incorrect except as an analogy), is a Factory that holds a reference to several Singletons (Used to hold the graphics/sprites for a single thing). Then, everything that needs to get a Sprite would ask the Factory for that’s Sprite Singleton, the Factory would build it (If it doesn’t exist), then give what’s asking it that singleton.

So you mean the Factory is not singleton, but holding static variable of sprites right?

This is where the terminology gets a little lacking, and ends up rather depending on how you decide to implement it.

The Factory doesn’t have to be a Singleton, it can be, but it doesn’t have to be. Especially if you’re providing different graphic modes (Think having multiple themes, or having different art sets). Instead, you’d have several Factories that are handed around to contain the different graphic modes.

Let me explain Flyweight in better detail first.

  1. FlyweightFactory- This class holds the instances to the Flyweight objects, and typically has a method of getting a specific Flyweight Object.
  2. FlyweightInterface<Interface/Abstract/ExtendableClass>- Defines the operations that a Flyweight has to provide. In the case of using them for graphics, this would be something like “drawAt(int x, int y)” or “drawFrameAt(int x, int y, int frameId)”. Basically handling all of the different methods for drawing a specific thing.
  3. ConcreteFlyweight- Implements/Extends the FlyweightInterface and provides the specifics of drawing the sprite where you want it. This allows you to remove the act of drawing from the Client (see next point).
  4. FlyweightClient- An object of some type that knows about the Factory and uses a FlyweightInterface (ConcreteFlyweight). This can be an Entity in your game, or something else. It’s what handles the ‘logic’ of whatever the object is.

Your ConcreteFlyweight would either directly hold an instance of your sprites, or would point to something that does. Since everything has to go through the FlyweightFactory to get to the Sprites (And since the FlyweightFactory ensures that there’s only one instance of each ConcreteFlyweight available through it) then you’re keeping your sprite memory usage to a minimum.

Well with above way you can avoid singleton. Just pass factory instance to each entity and make sure you construct the factory once in one class.

Yep, that’s exactly the point.

If you’re only going to have one graphic type, or think you’re going to need one Factory, you can make it a static class instead and have it act like a Singleton.

What I do now is just passing static instance of factory class.

That should be perfectly fine. Really, the only time you should worry about doing it another way is if you foresee some point in the future that your current code base will need to use multiple factories.

Either way, it’s good practice using another type of Design Pattern that a lot of people end up avoiding it seems.

Passing around the factory is the way to do it. You shouldn’t need to pass it around all that much, because inner classes can stand in for finer-grained factories. If you’re passing around the factory, you may as well make that an instance, if for no other reason than to cut down on the Class/Foo.class noise you have to bother with when passing around classes.

I don’t understand ???

If you use a static factory, like FooFactory, then the only way to pass it around between objects is to use “FooFactory.class”, and the only safe way to declare it is with Class. This is noisy and annoying, when you could instead just do “fac = new FooFactory()” then pass it in like any other object. Also, you can make FooFactory take args, like a configuration.

I think what Sproingie meant is that while you could just write in FooFactory.getFlyweight(id) everywhere you’re going to need to, that it’s not always a good thing to do so. Passing it like a parameter would be better, but as he said it would require the clunkiness of the Class class (Har har) to do so if all of the access is through static methods.

What I think Sproingie meant.


public class StaticTester {

    public static void doOp() {
        System.out.println("Op is did.");
    }
}


public class StaticExample {

    StaticTester staticObject;

    public StaticExample(StaticTester staticObject) {
        this.staticObject = staticObject;
    }

    private StaticExample(Class<StaticTester> aClass) throws InstantiationException, IllegalAccessException {
        this.staticObject = aClass.newInstance();
    }

    public void doOp() {
        System.out.println("Example did.");
        staticObject.doOp();
        System.out.println("Example did again.");
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        StaticExample se = new StaticExample(StaticTester.class);
        se.doOp();
    }
}

Using static methods also adds in the problem of how the static fields are initialized…
Do you have to call FooFactory.initialize() first? Which would mean that you would have to call FooFactory.initialize() prior to it being used anywhere and probably put in checks for many of the functions you’d use with it to ensure that it was initialized.


public class StaticTester {
    private static boolean isInit = false;
    private static String say;
    
    public static void initialize() {
        say = "We say this.";
        isInit = true;
    }
    
    public static void doOp() {
        if(isInit) {
            System.out.println(say);
        } else {
            throw new ClassNotInitializedException("This is made up!");
        }
    }
}

Do you use a static initialization block in the FooFactory code? However, this takes away a lot of your ability to decide when/where/how the information gets initialized as it is called when the class is first imported or used (Not completely certain there, but you don’t have control).


public class StaticTester {

    private static String say;

    static {
        say = "We say this.";
    }

    public static void doOp() {
        System.out.println(say);
    }
}

Having another class create it, or make the first call to some static method in FooFactory to get an instance of FooFactory, then passing it to each object takes care of those issues. It also makes replacing the factory easier (Going from static calls like FooFactory.method() to object.method() can be fun.)


public class StaticExample {

    StaticTester staticObject;

    public StaticExample(StaticTester staticObject) {
        this.staticObject = staticObject;
    }

    public void doOp() {
        System.out.println("Example did.");
        System.out.println(staticObject.getInitializationVariable());
        System.out.println("Example did again.");
    }

    public static void main(String[] args) {
        StaticTester.createInstance("New stringer string!");
        StaticExample se = new StaticExample(StaticTester.getInstance());
        se.doOp();
    }
}


public class StaticTester {

    private static StaticTester instance;
    
    public static void createInstance(String initializationVariable) {
        instance = new StaticTester(initializationVariable); 
    }
    
    public static StaticTester getInstance() {
        if(instance == null) {
            throw new ClassNotInitializedException("This is made up!");
        } else {
            return instance;
        }
    }
    
    private String initializationVariable;
    
    private StaticTester(String initializationVariable) {
        this.initializationVariable = initializationVariable;
    }
    
    public String getInitializationVariable() {
        return initializationVariable;
    }
}

PS-- If someone can tell me how to get Spoilers and Code to work together I’ll edit this. Also, if it’d be better to put all of these code snippets elsewhere do say so!