Help me get rid of a singleton

Started by
45 comments, last by RealMarkP 15 years, 10 months ago
Quote:Original post by Rydinare
I guess the question I'd have for you is how to eliminate the globals without passing the reference around all over the place. I've never seen a great answer to this other than a strict redesign to decouple things more.
Well, that's The Answer. There's no easy alternative answers. If it was easy, it wouldn't be design.
Advertisement
In the engine I was working on, I used two interfaces to indicate message users. MessageSender and MessageHandler. When a process (Renderer, InputController, GameStateStack) was added to the kernel it checked to see if the MessageSender or MessageHandler interface was implemented and if it was, set the MessageDispatcher property with the kernels instance of the MessageDispatcher.

Another way to handle it would be with dependency injection.
Quote:Original post by Sneftel
Quote:Original post by Rydinare
I guess the question I'd have for you is how to eliminate the globals without passing the reference around all over the place. I've never seen a great answer to this other than a strict redesign to decouple things more.
Well, that's The Answer. There's no easy alternative answers. If it was easy, it wouldn't be design.


[razz] True. I tend to use the mechanical steps that I mentioned as a first step, since removing the global is generally a step in the right direction. I guess, the question is, do you have any guidelines for the following steps or is kind of a case by case basis. I'm always wanting to experiment with more techniques that ultimately get you to a better design faster.
Common sense is the only useful guideline I can think of (though by itself it won't get you very far). One thing, though: Singleton-laden design encourages one to create objects where they're needed, with little thought as to whose responsibility it should actually be to create each one. So I guess the modification I'd make is, at each level where you (as the object) would add an object reference because your child needs it, ask yourself: do I know, or can I find out about, some other object which already has the right reference? Hopefully, the answer is yes, and that other object can handle the task of creating the child.

And the other thing is "lots of dependency injection" and "lots of small interfaces". "Class A telling class B something" has three ways of being made to happen: A knows B, B knows A, or C knows both A and B. Revel in the options.
Quote:Original post by Sneftel
Common sense is the only useful guideline I can think of (though by itself it won't get you very far). One thing, though: Singleton-laden design encourages one to create objects where they're needed, with little thought as to whose responsibility it should actually be to create each one. So I guess the modification I'd make is, at each level where you (as the object) would add an object reference because your child needs it, ask yourself: do I know, or can I find out about, some other object which already has the right reference? Hopefully, the answer is yes, and that other object can handle the task of creating the child.

And the other thing is "lots of dependency injection" and "lots of small interfaces". "Class A telling class B something" has three ways of being made to happen: A knows B, B knows A, or C knows both A and B. Revel in the options.


Sounds reasonable, although, one caveat I'd add is that common sense isn't often all that common. Convincing my coworkers that something as simple as, if your class has 100 methods, you might need multiple smaller classes, has been a real challenge. Most of them don't understand design patterns or anything of the nature. That's actually one thing I wish there was more of is some real solid mechanical-ish guidelines. You know, a way of quantifying code smell? I guess a few books hit it somewhat, but not completely, like Design Patterns and Object-Oriented Heuristics, but none quite to my satisfaction.
I used to have a singleton that managed messages, delayed messages, etc.

Now i have replaced all that with boost::bind and boost::signals (multi threaded version). And "updateable objects" wrapping those "messages" to be attached somewhere in the "update tree".

Until now, it works great :)
http://www.teatromagico.net
Boost's signaling might work in this case. I also thought about using a loop back network connection to my own application and named pipes. I think using either sockets or pipes might be a bit slow.

I'm also thinking about trashing this event manager design approach. Can anyone here recommend a substitute, or give an example of how they communicate between objects in their engine?
------------Anything prior to 9am should be illegal.
Quote:Original post by RealMarkP
Hello.

I'm currently using the singleton pattern for two classes. First being an error logging class (which I'm not too concerned about), and the second being my event passing system. This event system handles messages from all over the system and properly passes them along to other parts of the system, much like a regular message pump would (via PeekMessage, DispatchMessage).

I was wondering, since this class is accessed from many places to fire events, if there was a better pattern I could use to build this on. Or better yet, if anyone can suggest a better approach of routing events around my (fairly large) system.


First check that you aren't overcomplicating things. (I have no doubt that things could easily be as intrinsically complicated as you suggest, but troubleshooting requires these first steps. The exposition is often useful regardless.)

Do you even need "events" in the first place? Why?

Do the events really need to be "queued"? Why?

Does there really need to be a single event queue, or could each subsystem queue the events sent to it? Does the sender of an event, in general, know where it's going? If not, why not? (One common situation is that the event-sender is associated dynamically with an event-recipient; consider the Chain of Command design pattern. This can happen e.g. for GUI components in a tree, where "events" are passed up the tree - this can often be reduced to simple delegation.)

Quote:Original post by Rydinare
Sounds reasonable, although, one caveat I'd add is that common sense isn't often all that common. Convincing my coworkers that something as simple as, if your class has 100 methods, you might need multiple smaller classes, has been a real challenge.


YEESH.

You might try the Socratic method. Get them to realise the problems they've been having, and have them infer the source for themselves.
Quote:Original post by Zahlman
Quote:Original post by Rydinare
Sounds reasonable, although, one caveat I'd add is that common sense isn't often all that common. Convincing my coworkers that something as simple as, if your class has 100 methods, you might need multiple smaller classes, has been a real challenge.


YEESH.

You might try the Socratic method. Get them to realise the problems they've been having, and have them infer the source for themselves.


That's the problem. They never make the connection. These are the same guys who have been known to complain about COM's hard limit (apparently) of *only* allowing 255 methods and have complained that the STL string is a terrible class because it doesn't fully expose all of its internals so that you can modify the string with C-style methods (e.g.: sprintf, etc...). After the 90th time hearing the second argument, I gave up on trying to teach them but very small bits at a time. Though this has me tempted to make a thread where people list their coworkers bad programming habits.
Quote:Do you even need "events" in the first place? Why?


Events are one way to notify classes to change their internal state. For example, when I resize a window, I need to also resize my backbuffer. r, If my rendering context loses focus, I need to tell the resource pool to invalidate all my objects. So, without an event system, I would have my renderer directly modify the resource pool. Also, my window, once resized would tell the renderer to resize (as an example). This adds coupling in places that should be generic. As you can see, I would have to manage the relationship between my window and renderer, and my renderer and the resource pool. These are just examples and it could get complex and full of relationships that couples the code more. I just see it as a way to "broadcast" messages to the classes that care.

Quote:Do the events really need to be "queued"? Why?


Actually they are not queued. The event manager is just a glorified proxy that sends messages to listeners that want them. Its similar to the Mediator pattern, so objects don't communicate directly, rather through this mediator proxy.

Quote:Does there really need to be a single event queue, or could each subsystem queue the events sent to it?


I am wondering the same thing. I'll get back to you on this one, once I figured out the answer :P.

Quote:Does the sender of an event, in general, know where it's going?


No. When I send out an onDeviceLost message, Only the resource pool and renderer should care. An onSize message would only affect the window and renderer. An onKeyDown message should only affect the game logic, etc.

Quote:If not, why not? (One common situation is that the event-sender is associated dynamically with an event-recipient; consider the Chain of Command design pattern. This can happen e.g. for GUI components in a tree, where "events" are passed up the tree - this can often be reduced to simple delegation.)


I vaguely remember reading about this pattern. I'll look into it. Thanks :).

Quote:YEESH.

You might try the Socratic method. Get them to realise the problems they've been having, and have them infer the source for themselves.


It depends on how much time and patience you have. Forcing a student (co-worker) to figure things out by themselves is much more taxing on the teacher (you) then it would be if the teacher told the student directly. But the reward is heaven on earth when you can rub it in :D.

------------Anything prior to 9am should be illegal.

This topic is closed to new replies.

Advertisement