8

I worked on a project and found a working solution, but now I got some questions on how I solved some problems in the code. First of all, I am no expert in design patterns, but I know the (anti-)pattern of singletons and normally I avoid them. But what I use quite often, are static helper / utility methods.

So the project I've been working on is based on the Atlassian Plugin SDK. I implemented servlets, accessed some data via Atlassian components, all pretty straight forward. When it comes to the point of rendering pages, the Atlassian platforms use Apache Velocity. So I build my context map and access the objects in Velocity, everything is fine. At some point, I want to generate URLs to link to other servlets or pages. So, I create a class with static url generation methods. Sadly, I cannot access those methods in Velocity, because there is no instance I could pass to the Velocity context (which defines the scope). But Velocity allows me to use static methods via instances of the class. The resulting class looks like this (java code):

public class Urls {
    private static Urls Singleton = new Urls();

    public static Urls getInstance() {
        return Singleton;
    }

    private Urls() { }

    public static String getBaseUrl() { ... }

    public static String forUserProfile(ApplicationUser user) { ... }

    ...
}

Now, in my regular java code, I can simple use the static method:

String myUrl = Urls.forUserProfile(myUser);

But I can also pass my singleton to the velocity context ...

context.put("urls", Urls.getInstance());

... to use it in my Velocity template:

<a href="$urls.forUserProfile($myUser)">User profile</a>

I used this 'pattern' or similar ones several times in my project. Is there any name for something like this? I assume this is kinda rare, because normally one could simply access the static methods. Do you think there are any big disadvantages I forgot? Any reason not to use this way? Any better ways?

4
  • 2
    Why not allow for multiple instances of Urls and put them in the context like this: context.put("urls", new Urls());? Jan 19, 2017 at 12:50
  • @BartvanIngenSchenau: I commented on the answer of Caleth, because its exactly the same suggestion. Jan 19, 2017 at 12:59
  • 2
    Just in case: "a singleton without any state" is also known as "function". Maybe this POV might help.
    – 9000
    Jan 19, 2017 at 19:20
  • As per this question and answer you can can call static methods on class objects in your context. You'd use context.put("urls", Urls.class) and things should work as desired.
    – JimmyB
    Jan 21, 2017 at 12:03

4 Answers 4

9

A singleton is a fancy kind of global state.

Your Urls isn't usefully a singleton, because it has no state. You may as well just not instantiate it in normal code.

public class Urls {
    public Urls() { }
    // static methods ...
}

context.put("urls", new Urls());
7
  • 1
    Well, I was thinking about this, but would this really be better? To instantiate something normally means to define a state for an object, but this new object would have no state. In the end I would create multiple instances of exactly the same object (even if the garbage collector would destroy them after usage). For someone reading the code, wouldn't the new keyword indicate a new state? Jan 19, 2017 at 12:57
  • @lukegv Any method which doesn't read or change the internal state of an object and isn't supposed to be overridden by a derived class should usually be static. If a class consists only of static methods, there is usually no point in instantiating it.
    – Philipp
    Jan 19, 2017 at 12:59
  • 2
    @lukegv "wouldn't the new keyword indicate a new state?" No, it would indicate a new instance of the object. If the object has no state, then by all means provide a static method that returns the same instance each time, but making the constructor private, and thus creating a singleton, does nothing useful in your case.
    – David Arno
    Jan 19, 2017 at 13:01
  • @Philipp: Yeah, correct, thats why I wanted to prevent it by making the constructor private. Because of Apache Velocity, I need an instance of a 'static' class, so now there is a point in instantiating it. Jan 19, 2017 at 13:02
  • 3
    @lukegv: You should reserve the use of the Singleton pattern for those cases where having multiple instances will break your functionality. The Urls class does not fit that classification. Jan 19, 2017 at 16:24
2

Singleton without state is meaningless, so there is no need to enforce there being only one isntance. And if something needs instance, use instance.

BUT there can be state in seamingly stateless singleton. You can have multiple implementations and the state is what implementation you are using. And then requirement that whole system use same implementation makes sense, so making it some kind of injectable singleton (in java without exteral framevorks you can use ServiceLoader and create instance based on available implementations at runtime).

2

No such thing

There is no such thing as a singleton without state. The pointer to the single instance is state. This pointer not only identifies the one and only instance, but also defines the type of the instance and its VMT and/or dispatch table, meaning that it determines behavior as well.

I think you are asking about a singleton that returns an object that lacks member variables.

The only state that a singleton is required to manage...

...is the static variable that contains the reference to the One And Only Thing. Any other state is not endemic to the singleton pattern.

If there is no object state, why have a singleton?

A singleton is also a poor man's factory. A call to Instance must always return the same object, yes, but it may be an object of any type that inherits from the singleton class itself. Thus you may want to keep the singleton pattern for purposes of polymorphism. For example, maybe you have a DatabaseContext.Current sort of singleton that might return an OracleContext or SqlServerContext depending on config.

Don't forget forward compatibility

Even if your singleton doesn't have member variables right now, you may wish to add them later. They will be easy to add. If you do away with the pattern, it would be harder to restore later when the need for those member variables arises.

With regards to YAGNI-- As long as the singleton pattern maps conceptually onto your problem domain, and doesn't impose much additional work, it may still be a justified design decision, YAGNI notwithstanding.

Use DI instead

Everyone hates singletons these days. The more modern approach is to use dependency injection with per-process instances. With DI it is much easier to create the necessary isolation for automated unit testing.

1

One of the more unfortunate aspects of the Singleton pattern is it is widely understood to be much more simplistic than what is described in the GoF Patterns book. It's really subtle but if you look at the code examples for that pattern, you will see an abstract Singleton class with multiple concrete implementations. Most people think of Singleton as simply a global object but that's not really correct.

If you ignore that, then, no it doesn't make any sense to have a Singleton without state. If however, you consider polymorphism, it can. For example, lets say you have an application where you need to be able to configure global rules for how certain accounting calculations are implemented such as rounding. So you have class like so:

public abstract class Accounting
{
   public static final Accounting getInstance()
   {
     //...
   }

   public abstract Money round(Money money);
}

You would then create different versions of this Accounting class and then implement some sort of way to configure which one was used in a given instance of the application. It's not really crucial that these objects contain state in order to be useful. The ability to use them to swap out method implementations is enough.

DI is more in-vogue for this kind of thing and it does offer a lot more flexibility. If that flexibility is not needed or actually creates risks, I think it's worth considering a polymorphic Singleton approach. There's also nothing preventing you from using DI to configure the singleton instance in this approach.

Based on past experience it's likely someone will claim that I am not describing the Singleton pattern and point to some web page as proof. I would ask anyone with that opinion to actually read the pattern including the examples in the GoF book. Most websites that explain this pattern are really just explaining how to implement global objects.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.