views:

1167

answers:

12

I tend to declare as static all the methods in a class when that class doesn't require to keep track of internal states. For example, if I need to transform A into B and don't rely on some internal state C that may vary, I create a static transform. If there is an internal state C that I want to be able to adjust, then I add a constructor to set C and don't use a static transform.

I read various recommendations (including on stackOverflow) NOT to overuse static methods but I still fail to understand what it wrong with the rule of thumb above.

Is that a reasonable approach or not?

Thanks

+3  A: 

That seems to be a reasonable approach. The reason you don't want to use too many static classes/methods is that you end up moving away from object oriented programming and more into the realm of structured programming.

In your case where you are simply transforming A to B, say all we're doing is transforming text to go from

"hello" =>(transform)=> "<b>Hello!</b>"

Then a static method would make sense.

However, if you're invoking these static methods on an object frequently and it tends to be unique for many calls (e.g. the way you use it depends on the input), or it is part of the inherent behavior of the object, it would be wise to make it part of the object and maintaining a state of it. One way to do this would be to implement it as an interface.

class Interface{
    method toHtml(){
        return transformed string (e.g. "<b>Hello!</b>")
    }

    method toConsole(){
        return transformed string (e.g. "printf Hello!")
    }
}


class Object implements Interface {
    mystring = "hello"

    //the implementations of the interface would yield the necessary 
    //functionality, and it is reusable across the board since it 
    //is an interface so... you can make it specific to the object

   method toHtml()
   method toConsole()
}

Edit: One good example of great use of static methods are html helper methods in Asp.Net MVC or Ruby. They create html elements that aren't tied to the behavior of an object, and are therefore static.

Edit 2: Changed functional programming to structured programming (for some reason I got confused), props to Torsten for pointing that out.

MunkiPhD
I don't think using static methods qualifies as functional programming, so I'm guessing you mean structured programming.
Torsten Marek
+2  A: 

An object without any internal state is a suspicious thing.

Normally, objects encapsulate state and behavior. An object that only encapsulates behavior is odd. Sometimes it's an example of Lightweight or Flyweight.

Other times, it's procedural design done in an object language.

S.Lott
I hear what you're saying, but how can something like a Math object encapsulate anything but behaviour?
JonoW
He just said suspicious, not wrong, and he's absolutely right.
Bill K
@JonoW: Math is a very special case where there are many stateless functions. Of course, if you're doing Functional programming in Java, you'd have many stateless functions.
S.Lott
A: 

As long as not internal state comes into play, this is fine. Note that usually static methods are expected to be thread-safe, so if you use helper data structures, use them in a thread-safe manner.

Lucero
+3  A: 

The other option is to add them as non-static methods on the originating object:

i.e., changing:

public class BarUtil {
    public static Foo transform(Bar toFoo) { ... }
}

into

public class Bar {
    ...
    public Foo transform() { ...}
}

however in many situations this isn't possible (e.g., regular class code generation from XSD/WSDL/etc), or it will make the class very long, and transformation methods can often be a real pain for complex objects and you just want them in their own separate class. So yeah, I have static methods in utility classes.

JeeBee
+1  A: 

The reason you are warned away from static methods is that using them forfeits one of the advantages of objects. Objects are intended for data encapsulation. This prevents unexpected side effects from happening which avoids bugs. Static methods have no encapsulated data* and so don't garner this benefit.

That said, if you have no use of internal data, they are fine to use and slightly faster to execute. Make sure you aren't touching global data in them though.

  • Some languages also have class-level variables which would allow for encapsulation of data and static methods.
Steve Rowe
A: 

I recently refactored an application to remove/modify some classes that had been initially implemented as static classes. Over time these classes acquired so much and people just kept tagging the new functions as static, since there was never an instance floating around.

So, my answer is that static classes aren't inherently bad but it might be easier to start creating instances now, then have to refactor later.

overslacked
+26  A: 

There's two kinds of common static methods:

  • A "safe" static method will always give the same output for the same inputs. It modifies no globals, and doesn't call any "unsafe" static methods of any class. Essentially, you are using a limited sort of functional programming -- don't be afraid of these, they're fine.
  • An "unsafe" static method mutates global state, or proxies to a global object, or some other non-testable behavior. These are throwbacks to procedural programming, and should be refactored if at all possible.

There are a few common uses of "unsafe" statics -- for example, in the Singleton pattern -- but be aware that despite any pretty names you call them, you're just mutating global variables. Think carefully before using unsafe statics.

John Millikin
This was exactly the problem I had to solve - the use, or rather misuse, of Singleton objects.
overslacked
A: 

If you know you will never need to use the internal state of C, it's fine. Should that ever change in the future, though, you'd need to make the method non-static. If it's non-static to begin with, you can just ignore the internal state if you don't need it.

Adam Crume
A: 

I used to go back and forth between a class with a bunch of static methods and a singleton. Both solve the problem, but the singleton can be much more easily replaced with more than one. (Programmers always seem so certain that there will only be 1 of something and I found myself wrong enough times to completely give up on static methods except in some very limited cases).

Anyway, the singleton gives you the ability to later pass something into the factory to get a different instance and that changes the behavior of your entire program without refactoring. Changing a global class of static methods into something with different "backing" data or a slightly different behavior (child class) is a major pain in the butt.

And static methods have no similar advantage.

So yes, they are bad.

Bill K
A: 

This is really only a follow up to John Millikin's great answer.


Although it can be safe to make stateless methods (which are pretty much functions) static, it can sometimes lead to coupling that is hard to modify. Consider you have a static method as such:

public class StaticClassVersionOne {
    public static void doSomeFunkyThing(int arg);
}

Which you call as:

StaticClassVersionOne.doSomeFunkyThing(42);

Which is all well and good, and very convenient, until you come across a case where you have to modify the behaviour of the static method, and find that you are tightly bound to StaticClassVersionOne. Possibly you could modify the code and it would be fine, but if there was other callers dependent on the old behaviour, they'll need to be accounted for in the body of the method. In some cases that method body can get pretty ugly or unmaintainable if it tries to balance all these behaviours. If you split out the methods you may have to modify code in several places to take account of it, or make calls to new classes.

But consider if you had created an interface to provide the method, and given it to callers, now when the behaviour has to change, a new class can be created to implement the interface, which is cleaner, more easily tested, and more maintainable, and that instead is given to the callers. In this scenario the calling classes don't need to be altered or even recompiled, and the changes are localised.

It may or it may not be a likely situation, but I think it is worth considering.

Grundlefleck
A: 

I'd consider it a design smell. If you find yourself using mostly static methods, you probably don't have a very good OO design. It's not necessarily bad, but as with all smells it would make me stop and re-evaluate. It hints that you might be able make a better OO design, or that maybe you should go the other direction and avoid OO entirely for this problem.

patros
+1  A: 

Static classes are fine as long as they're used in the right places.

Namely: Methods that are 'leaf' methods (they do not modify state, they merely transform the input somehow). Good examples of this are things like Path.Combine. These sorts of things are useful and make for terser syntax.

The problems I have with statics are numerous:

Firstly, if you have static classes, dependencies are hidden. Consider the following:

public static class ResourceLoader
{
    public static void Init(string _rootPath) { ... etc. }
    public static void GetResource(string _resourceName)  { ... etc. }
    public static void Quit() { ... etc. }
}

public static class TextureManager
{
    private static Dictionary<string, Texture> m_textures;

    public static Init(IEnumerable<GraphicsFormat> _formats) 
    {
        m_textures = new Dictionary<string, Texture>();

        foreach(var graphicsFormat in _formats)
        {
              // do something to create loading classes for all 
              // supported formats or some other contrived example!
        }
    }

    public static Texture GetTexture(string _path) 
    {
        if(m_textures.ContainsKey(_path))
            return m_textures[_path];

        // How do we know that ResourceLoader is valid at this point?
        var texture = ResourceLoader.LoadResource(_path);
        m_textures.Add(_path, texture);
        return texture; 
    }

    public static Quit() { ... cleanup code }       
}

Looking at TextureManager, you cannot tell what initialisation steps must be carried out by looking at a constructor. You must delve into the class to find its dependencies and initialise things in the correct order. In this case, it needs the ResourceLoader to be initialised before running. Now scale up this dependency nightmare and you can probably guess what will happen. Imagine trying to maintain code where there is no explicit order of initialisation. Contrast this with dependency injection with instances -- in that case the code won't even compile if the dependencies are not fulfilled!

Furthermore, if you use statics that modify state, it's like a house of cards. You never know who has access to what, and the design tends to resemble a spaghetti monster.

Finally, and just as importantly, using statics ties a program to a specific implementation. Static code is the antithesis of designing for testability. Testing code that is riddled with statics is a nightmare. A static call can never be swapped for a test double (unless you use testing frameworks specifically designed to mock out static types), so a static system causes everything that uses it to be an instant integration test.

In short, statics are fine for some things and for small tools or throwaway code I wouldn't discourage their use. However, beyond that, they are a bloody nightmare for maintainability, good design and ease of testing.

Here's a good article on the problems: http://gamearchitect.net/2008/09/13/an-anatomy-of-despair-managers-and-contexts/

Mark Simpson