These is basically patterns where you’re better off avoiding them. Seriously, just skip those parts of the book:
All patterns are a trade-off. The trade-off with singleton is reducing the number of parameters certain functions take and trading them for more static methods. From the perspective of code agility, a every method on singleton might as well be a static method. Not only that, but everything the singleton touches might as well be a static method. The testing implications of the Singleton pattern are horrendous. Steve Yegge has written far more than I intend to on the subject, so I’m really not going to spend any more time on telling you what a stupid, stupid idea it is. Singletons, static methods and global variables all expose the same problem. In fact, they’re pretty much effectively the same thing most of the time.
So, what should you do instead of a singleton? Well, let’s say, for instance, that you have a network connection (call it X) wrapped as an XConnection object. There’s only one physical connection, and that needs to be accessed from various parts of the system. Well, actually, the answer is very simple: you pass the object into the contructor of the objects that need it. If some of those objects get created before the network connection gets called, you could pass in an object that creates the connection on the first call, or you could pass in a promise/lazy object/future/whatever it’s called in the language of your choice. Basically, take the static methods you were thinking of, and turn them into instance methods.
Now, the technique that we’ve just described is called Dependency Injection (DI), and is made easier by using a DI container. Ironically, you tend to tell the container that the connection object has a “Singleton” lifecycle. But all that means is that there’s one connection referenced by the container, not one connection usable in the whole of your memory space. The distinction may appear small, but it’s the difference between a flexible design and a brittle nightmare. Much as certain extremely talented people may use the technique, don’t make your container a singleton. That way lies madness.
Singletons are, of course, a special case of the concept of shared state. In general terms, state and especially shared state, is problematic. Designs that share very little state or, even better, have no state at all tend to be less prone to hard to analyze bugs and easier to repurpose when requirements change.
This one basically says you shouldn’t create your objects, you should copy them. We already know this concept in .NET, it’s called ICloneable. There’s all sorts of problems with cloning objects, number one of which is that it’s not that well defined. If X has Y as a property, when you clone X, do you clone Y? Seriously, semantically, the prototype pattern is a mess.
The BCL team were talking about demising ICloneable five years ago.
The thing with prototype is: you can see how it might look sensible if you’re a C++ programmer. Copy means something quite specific: a memory-based clone. Any good C++ developer would know exactly what that would do. It’d copy things declared as values and re-use things declared as pointers. Let’s just think about that for a second: what happens when your data structure changes a value to a reference? Well, the semantics of your copy change. And, of course, you can’t copy anything that uses an external resource.
On the other hand, it’s important to note that sometimes context is everything.
The Singleton and Prototype pattern have no place in the arsenal of the educated C# developer. Prototype just makes no real sense, Singleton will positively ruin your code. Most people know that singleton is a bad idea, but are still enamoured with the concept of shared state. On the other hand, I don’t think anyone is seriously attempting to use the prototype pattern in C# in the first place.
EDIT: Thanks to Svend Koustrup for pointing out a dangling sentence.