Re: Singletons
- From: Sasa <sasa555@xxxxxxxxx>
- Date: Mon, 24 Jul 2006 18:13:07 +0200
H. S. Lahman wrote:
The example is the GoF book is one. Suppose you have an application that must stream error messages to a log file from multiple contexts where errors might occur. It is critical that there be only one ErrorFile instance open to handle all those messages. But each context may be in a different subsystem and thinks it should initialize the error file when it is initialized.
Yes, but this could also be resolved with passing parameters around?
Possibly. But the more common alternative is to simply create a single instance in a situation where there is only one opportunity to create it (e.g., at startup). One then forms normal relationships that always lead to that instance. IOW, one modifies the context where instantiation occurs.
What does it mean "forms normal relationship that always lead to that instance" and "modifies the context where instantiation occurs"?
What if in the future for some reason you actually want to change that, and have different contexts trace to different files? Wouldn't it be fairly difficult to refactor the singleton based solution?
Probably not. Singleton is really just a specialized factory object. The clients effectively ask it to create an object and it returns the singleton reference _as if_ it had been newly created. So if you need more instances you substitute a different factory object.
Singleton to me is not a factory. It is the one and only instance of the object. The GetInstance() returns reference to a single instance of the object. It may create it on the first access in case of lazy initialization, but its purpose is to retrieve it.
So while I can agree that substituting with different factory might work with tweaking, I don't find it very elegant.
That problem can actually be solved without Singleton but there are other contexts that are more difficult. For example, in a networking situation one may need to send multiple message packets for a single message. Typically one wants to open/close one channel around the message and use it for each message packet. If the most common mode is for single packet messages, one might try to open a channel at the packet level. Singleton then provides a performance optimization by simply returning the existing instance handle when there is more than one packet.
I don't understand - why wouldn't one always open the channel at the message level?
Because many network protocols limit the size of the message so it has to be split up into separate packets. Those packets will be sent rapidly so one can avoid the overhead of channel allocation if one sends them all over the same channel. Also, depending on the configuration, using the same channel may make it easier to keep track of what packets need to be reassembled into a single message on the other end.
I still don't understand, why can't you open the channel at the message level. The packets are parts of message, hence all packets will use the same channel.
Similar situations arise when resolving nonfunctional requirements using patterns like Strategy. One only needs a single instance of each of the Strategy subclasses regardless of the number of Context clients.
Doesn't that make sense only if strategy is stateless?
Yes. Strategy should be stateless in most situations. It is a delegation of behaviors. It gets its data from the Context object.
What if Strategy subclass uses member variables to keep its internal state which is irrelevant to the outer world (some accumulating data etc)?
However, the Context objects may not always be required and, even if
This puzzles me. Isn't the Context synonim for the client of the strategy?
No. The GoF patterns never show the client because it would always look the same. What one really starts with for most GoF patterns is:
[Client]
| *
|
| R1
|
| accesses
| 1
[Context]
But the problem is that the [Context] object may need to respond differently in different collaboration contexts. One cannot capture that dynamic variation in a simple static association, so one uses delegation and polymorphic dispatch to make the dynamic nature more obvious:
[Client]
| *
|
| R1
|
| accesses
| 1
[Context] ---------------------- [Strategy]
* R2 1 A
|
...
Thus [Strategy] represents a delegation from the [Context] object that is largely transparent to the [Client]. [Note the [Strategy] is-a tree is essentially an application of the Template pattern to the delegation to provide the polymorphic dispatch.]
Understood, thank you for the elaboration.
they do exist, they may not require the Strategy role in certain situations or may not require all of the subclasses. If the Context objects are created in quite different contexts within the application one has a problem deciding whether one needs to actually instantiate the Strategy tree elements or not.
Well, I usually instantiate specific strategy every time someone needs it. I do it through some isolated function so I have the chance of optimizing if necessary. Singleton could be the optimization in case of pure stateless concrete strategy classes, but even the I wouldn't make those classes as singleton, but rather have their instantiator holding the single instance to them (obtained via constructor and not via static GetInstance method).
In many situations instantiating a [Strategy] object every time it is needed would be inefficient because of the overhead of heap operations.
And in many situations it is no issue at all.
I do think though, that instantiating it always is simpler approach of the two and would devise some way of resolving performance issues only when they arise.
FWIW, IME the most common reason for using Singleton arises from dealing with non-functional requirements like performance. While there are customer problem spaces where the one-instance requirement is quite explicit, they tend to be pretty rare or they are trivial to enforce in the normal flow of control (i.e., Singleton never becomes an issue in the natural solution).
Thank you, I am of a similar oppinion. It might make sense that some class has one instance per defined context, however future requirements might call for different contexts to use different instances. I feel that simply ensuring that the context uses one instance (but not with singleton) is more flexible approach.
Still, the sentence from your original post in this thread puzzles me.
"Singleton enforces a business rule that there can only be one instance of a problem space entity regardless of how many opportunities there may be for instantiation at run time."
Isn't this contradiction, or am I missunderstand something?
The tricky part in using Singleton is deciding if the single instance requirement can be handled in another way. For example, in the ErrorFile example, one could create one instance of ErrorFile at startup and simply pass a handle to it to each subsystem when it is initialized. IOW, one just reorganizes the way the instance is created so that there is only one opportunity to create it (startup).
Exactly!
I am currently thinking that passing parameter around is always the way to go. Singleton seems very restrictive. It means I cannot have more than one instance. If for whatever reasons I want to change it, I might encounter significant refactoring, if I have MyClass::GetInstance() calls spread around the code.
What is your oppinion on this?
I don't of it in terms of passing parameters. I see that as just a mechanism for instantiating a relationship to ErrorFile. The real issue to me is where and when one does the instantiation. IOW, the big question is: Can one find a <reasonable> way to organize the flow of control in the solution so that there is only one opportunity to instantiate the object? If so, one doesn't need Singleton to enforce the one-instance requirement.
The question still remains - when does one need Singleton?
Sasa
.
- Follow-Ups:
- Re: Singletons
- From: H. S. Lahman
- Re: Singletons
- References:
- Re: Singletons
- From: Robert Martin
- Re: Singletons
- From: H. S. Lahman
- Re: Singletons
- From: Sasa
- Re: Singletons
- From: H. S. Lahman
- Re: Singletons
- From: Sasa
- Re: Singletons
- From: H. S. Lahman
- Re: Singletons
- Prev by Date: Re: Observer pattern limitations
- Next by Date: Re: What is polymorphism?
- Previous by thread: Re: Singletons
- Next by thread: Re: Singletons
- Index(es):
Relevant Pages
|