Channels ▼

Arnon Rotem-Gal-Oz

Dr. Dobb's Bloggers

Refactoring the GoF Patterns (Singleton in .NET continued)

April 22, 2008


Among the reactions I got for my previous post on the Singleton pattern in .NET were a couple that talked about the design rationale behind the solution I posted.

Adi Avnit posted on the risk of using a "generic singleton":

However, there is one possible pitfall to this approach, as it makes this code possible:
Singleton obj = Singleton.Instance;
MyClass obj2 = new MyClass();

While I personally like the idea of having the freedom to use the same class in two different ways throughout the application, I know some people like their Singletons - well, single.
On the other hand, if you write a class from the start as a Singleton this is not an issue.

There is an inherit risk in decoupling a class from it's expected behavior, so take this into consideration before using this pattern."

And Cade Roux wrote in a comment:
Don't believe discoverability was a motivation for Singleton. The purpose was to ensure only one instance existed (a print spooler, a file system). You can get discoverability through the technique you explain but the primary purpose of singleton was a pattern of prohibition - to stop a programmer doing something they shouldn't do by accident by enforcing the primary goals of single point of access.

It is more than a global, and the OP, while comparing them to globals, does not acknowledge that this solves many of the problems which made "global" a 4-letter word. Knee-jerk reaction against globals is not healthy once you've mitigated their drawbacks.

It is true that usage of singleton can be misguided and cause coupling - which is why you need to ensure that the usage of the pattern matches the motivation in the first place.

This is a key point of design patterns which Alexander should have made clear in http://en.wikipedia.org/wiki/N...is_of_Form - the pattern is a result of a resolution of system of forces. It only satisfies that system - moving it to another different system will result in poor fitness. "
I guess that's a good opportunity  to talk about design issues regarding Design Patterns in general and the GoF ones in particular.

Aristotle Pagaltzis
noted (in a comment on Cedric's blog) that
Design patterns are a sign of a deficiency of a language for the purpose that the design pattern addresses. In other words, the Visitor pattern used in Java points to the fact that Java is deficient in terms of list processing: the `map` and `filter` constructs need to be emulated with lengthy OO incantations."
In other words, Concrete patterns* (like GoF's) are tied to implementation which means that the implementation language is  part of their "context". Thus when you come to apply a pattern in a different language you need to consider the language in use and make sure that:
  1. The pattern is needed
  2. The solution in the pattern is the best one for the language.

Let's look at a few examples.


If we take the Visitor pattern mentioned above, the intent of the Visitor pattern is to "represent an operation to be performed on the elements of an object structure without changing the classes of the elements". In .NET 3.5 you can do that with the use of LINQ (to find relevant items) and extension methods (to add external functionality) -- same intent, completely different implementation.

In the case of the Singleton pattern (mentioned in the previous post), the intent is to "Ensure a class only has one instance, and provide a global point of access to it". An implementation using templates (or generics) is superior since it provides the same intent but also adds better compliance with the Single Responsibility Principle. While it is possible to create the class as a non-singleton on the one hand it solves the multi-threading issue in one place preventing both duplication of code and mistakes (again this can be especially important in non-forgiving environments like C++). It also lets you (not in the implementation I provided) add flexibility and e.g. let singletons die and (if needed) resurrect themselves etc. Note that even if you are not convinced that using generics is better, there's no doubt that using .NET's thread-safe static readonly variable (public static readonly MySingleton = new MySingleton();)  is a much simpler solution than the GoF one and again, answers the original intent with a different solution.

Another example would be the Template method pattern. The idea behind the template method is to support the Open closed principle (classes should be open for extension but closed for modification) or as the GoF defines the intent:

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm strucuture"
.NET 3.5 supports the notion of Generic Delegates so you can define functions as parameters and pass them along. This is a better implementation than the template method as now you don't have to subclass when you want to extend an algorithm you can just pass a function that matches the signature; for  example:

<span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px">    <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">class</span> Program<br />    {<br />        <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">static</span> <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">void</span> Main(<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">string</span>[] args)<br />        {<br />            var alg <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px">=</span> <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">new</span> Algorithm();<br />            alg.DoSomething(Funky);<br />        }<br /><br />        <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">static</span> <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">bool</span> Funky(<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">string</span> value)<br />        {<br />            <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">return</span> value == <span style="color: #666666; background-color: #e4e4e4; font-family: Courier New; font-size: 11px">"somevalue"</span>;<br />        }<br />    }<br /><br /><br />    <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">class</span> Algorithm<br />    {<br />        <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">public</span> <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">void</span> DoSomething(Func<<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">string</span>,<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">bool</span>>CanGoForward)<br />        {<br />            <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">string</span> someVariable <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px">=</span> <span style="color: #666666; background-color: #e4e4e4; font-family: Courier New; font-size: 11px">"somevalue"</span>;<br /><br />            <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">if</span> (<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">null</span>!=CanGoForward && CanGoForward(someVariable))<br />            {<br />                <span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px">//do one step</span><br />            }<br />            <span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px">// whatever</span><br />        }<br />    }</span>


You should note that this "refactoring to fit the language" phenomena isn't limited to GoF patterns (or .NET :));  for instance, you can consider the use (or lack thereof) of Dependency Injection in languages such as Ruby which I wrote about a few months ago.

To sum up: When you talk about design patterns, you need to consider the implementation language. The design pattern deals with deficiencies in the language and different languages have different deficiencies and may have better solutions to the problems solved by the patterns.



* As opposed to architectural patterns which are more abstract and thus more reusable (e.g. Hohpe & Wolf Enterprise integration patterns, or Martin fowler Enterprise Architecture patterns)

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video