• Forum
  • Lounge
  • Alternative to the classic Singleton Res

 
Alternative to the classic Singleton ResourceManager?

So we all know about how singletons are considered bad style and it's often misused. (It's used as a means of creating a global access point to a class, instead of the original idea, making sure there's only ONE instance of the class at any given time.)

So my question to y'all i now: How can you implement a resourcemanager WITHOUT havind it as a global or singleton?
I'm not sure I follow, when you say resource manager I immediately think of shared_ptr's or the likes, I don't really think of a singleton. So to answer your question, implement a reference counting class that is not a singleton, is copyable and moveable where moving does not increase or decrease the counter. Is this what you are asking? Fun topic either way.
My question is not HOW to implement a resourcemanager, but how do you make it available to all the objects who need it without making it either a global variable or a singleton?
Resource managers are like the one place where a singleton is not only a good solution, but possibly one of the best solutions. Because at its very core you would want EVERYWHERE in your program to ALWAYS share the same resources. No point in loading the same resource multiple times just because multiple different areas of the program use it.

My advice: don't sweat it. Use a singleton. It makes sense here.

Why are you opposed to it?
Make it a static class?
closed account (3hM2Nwbp)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// Forward declare to avoid cyclic inclusions
class ResourceManager;

class MyGame
{
  public:
    MyGame(const ResourceManager& manager)
      : manager(manager)
    {
      
    }

    inline const ResourceManager& getResources(void) const
    {
      return manager;
    }

  private:

    const ResourceManager& manager;
};

class ResourceManager
{

};

int main()
{
  ResourceManager rm1;
  MyGame mg1(rm1);
  ResourceManager rm2;
  MyGame mg2(rm2);
  // I actually needed to have the ability to run multiple game instances 
  // when implementing a "limited vicarious view" of other players on a
  // multiplayer game job before.  In the end, it was less work to simply
  // attach another window with another game state, only feeding the 
  // client what they needed to know.  Sure, a singleton would have 
  // worked for it, but what if the other view's resources needed to be changed
  // in a slight way?  Surely it would have made more sense to load multiple
  // resource managers than to hack around what needed to be changed.
}


* Guess an explanation would help

MyGame - Contains references to the objects that a game instance uses. A pointer / reference to this class may be passed to whichever classes need it.

ResourceManager - Typically loaded through an interface so that any type of resource population can happen (SQL, XML, etc)
1
2
3
4
5
class ResourceLoader
{
  public:
    virtual void loadResources(ResourceManager& manager) = 0;
};


Disclaimer 1:
It might not be the best or cleanest way to do it, but that's how I had it set up.

Disclaimer 2:
I don't really consider myself to be a game developer.

* Final edit - I really click that button too many times...
As Disch said, singletons are perfect for all but a few freak occurrences. What I've hoped to accomplish with this post is just simply answering your question, ensuring that a resource manager is instantiated only once (per instance) without using a singleton pattern.
Last edited on
This situation is actually why I feel a singleton should be generally preferred in this case.

With the above approach you are loading the same resource multiple times. Once for each instance. All that really does is consume memory and performance. If all instances are using the same resource pool, it's more effective for them to all use the same resource manager.

In general resources are static data and do not change throughout the lifetime of the game. If they do change, they're probably not really a resource and don't belong in a resource manager (or at least not this general kind of resource manager).
closed account (3hM2Nwbp)
@Disch

I agree and disagree.

Agree: If all instances use the same resource pool, yes, they should all use the same manager. It would be absurd not to use the singleton pattern in this case.

Disagree: If resources need to be tweaked per instance, I do not feel that disqualifies them from being considered "resources", so long as tweaking happens during the loading phase.

*removed personal example of justification of view. It is irrelevant to the OP's question.
Last edited on
Again, why not use a static class?
closed account (3hM2Nwbp)
(Hate to play the devil's advocate, but here goes.)

@chrisname

With a static class, you're not only ensuring that an instance of the game is using the provided resource manager, but rather the entire executable. This may not be desirable in some cases.

Advocate aside: Singleton / Statics are usually desirable.
Ok, I can see how a singleton would be better.
closed account (3hM2Nwbp)
@chrisname

how a singleton *could* be better.

It's all in respect to the requirements of the program :)

It could be very possible (and usually is) that a static class solution would be the easiest to implement, extend, and manage for a game. What I'm advocating in this thread is that there isn't a one-size-fits-all, iron-clad design pattern for every project.
Last edited on
I don't think anyone was advocating a one-size-fits-all solution, just that the best solution to OP's problem is a singleton. Point taken, however.
Luc Lieber wrote:
Disagree: If resources need to be tweaked per instance, I do not feel that disqualifies them from being considered "resources", so long as tweaking happens during the loading phase.


I agree. But why not treat both tweaked and untweaked versions as two different resources and make them both accessable to all objects simultaneously?


The point I'm getting at is if you have resource data that is constant (at runtime) -- what is the benefit of loading it more than once and storing it in multiple places? I can't think of one. In that event, all the things that normally work against singletons/globals actually work to their benefit in this case. They indescriminantly are available for everything everywhere, and everyone shares the same data.

For data that changes at runtime, that's very messy. But for resource data it is pretty much ideal.
Last edited on
closed account (3hM2Nwbp)
@Disch

What happens when a third, fourth, and X different resource versions are later on deemed necessary by the project's owner(s)? I'm sure you know how important backward compatibility is to a long-term project that experiences regular content updates. I don't see how making all versions of resources available to every instance could be a good thing. In fact, all that I see is a source of potential misinterpretations / bugs for content developers, especially in an open-source environment. I am of course assuming that more people than the API's creator are in charge of content development, which is the case in many situations.

My next question is:

Since virtually the same memory overhead is still involved using either one or two management classes, and in all notable performance aspects is most likely negligible on modern hardware, why can't we have two separate managers for separate resource sets that are encapsulated in a more restrictive scope?

I now regret that I had removed the use-case scenario from a previous posting. That would do well in a separate thread, however.
Last edited on
What happens when a third, fourth, and X different resource versions are later on deemed necessary by the project's owner(s)? I'm sure you know how important backward compatibility is to a long-term project that experiences regular content updates.


I fail to see the relevance here.

The resource manager just handles the loading and ownership of resources at runtime. It doesn't really play a role in the overall maintenance of the resources themselves (at least not in the sense it sounds like you're describing).

I don't see how making all versions of resources available to every instance could be a good thing.


They wouldn't be. The only resources available would be the ones available (ie, whatever the user has on their machine).

In the case of content updates, the resources themselves are what would change... the manager wouldn't need to. Presumably, a semi-intelligent updater would remove resources no longer necessary and replace them with new ones.


why can't we have two separate managers for separate resource sets that are encapsulated in a more restrictive scope?


Because now you have to keep track of which manager has X version of Y resource.

That's not to say that can't be benefitial. I mean I can see the value to what you're going for here. Multiple ("sub") managers can help keep things organized if you have a very high number of resources. But ultimately any sub managers should get their resource data from one, final, "master" manager which actually owns the resource, in the event that a resource is used in multiple sub categories.




Please don't write off my debating as disagreement. I'm actually very interested in your view here and am just trying to understand it. More than a few times my opinion has been changed after discussions like this. =)
closed account (3hM2Nwbp)
@Disch

Later on tonight I'll PM you the use case scenario that made me come up with that solution.
I'm having a somewhat relevant problem. How to elegantly manage resources in a half-functional code? (Scala).
What I want is something like
object Resources {
   val foo = Image.Load("foo.png")
}
The problem is that Image.Load, for some reason needs to be called after initializing graphics.

Of course, I could do
object Resources {
   var foo = null
   def init() {
      foo = Image.Load("foo.png")
   }
}
and then in main,
Graphics.init()
Resources.init()
It's a bit ugly though.

What I did was make foo a lazy val. It works, but is a bit of a hack.

I could make Resource a class, create an instance after Graphics.init() and pass it around, but I don't like this, since, as far as my functional code is concerned, Resources is a constant. Although this might be the most correct way.
Topic archived. No new replies allowed.