I'm refactoring some code and I'm looking at a class called HFile. HFile has all private constructors so that you can't actually create instances of it. Instead of creating instances of HFiles as follow:
var file = new HFile('filename')
file.Save()
all HFile interaction is handled via static methods. So if I wanted to save a file I would call:
HFile.save('filename')
and then internally an instance of HFile would be created and then saved. Obviously without knowing the whole story any reader must reserve judgment, but it seems like using static methods has become very fashionable at my place of work. So I'm wondering if there are good principles/best practices for usage of static methods that can helpful for a group of guys sitting down and reviewing their usage of static methods.
In general, if your situation requires encapsulation of state or an organizational structure, then you will be using classes.
On the other hand, if you have something that is a cross-cutting concern, and can be used broadly across your application, you might consider methods in a static utility class. System.Math
in the .NET framework (and Java) is an example of this.
In your example, HFile is probably an object with state, so I would not generally use a static method to save it. It's simpler just to make a method call on the specific HFile object, rather than having to pass the entire object to a static method for saving. Whether that makes sense or not in your particular application depends on whether your application's paradigm sees HFile objects as things to be passed around and acted on by outside methods, or as standalone objects capable of saving themselves.
Lots of static methods/static classes is a symptom of proceduralitis -- writing procedural code in an object-oriented language. The best way that I know of to eliminate this kind of thinking is a thorough understanding of object-oriented principles and practices. Using test-driven development and forcing code to be testable will help, because it is much harder to write tests for static classes. Eventually, if you use TDD you naturally gravitate towards more decoupled, OO architectures, if only to ease the testing pain.
Static methods are hard to test because you can't mock them out. For this reason we tend to avoid them at my place of work. Though we do use them for factory methods.
I wouldn't worry about the number of static methods so much as I would about what these methods are doing. A static method that returns a value, or modifies an object that you pass as an argument? No big deal. A static method that modifies private static fields? I worry. A static method that modifies public static fields belonging to other classes? I need to lie down in a darkened room with a damp washcloth on my brow.
This isn't very object oriented, is it. Now maybe your place doesn't really like OO code, and that's fine. But if you want to encapsulate data and methods, then you need instance methods to work on that data.
An abundance of static methods is probably associated with lots of global variables. Eg. the info that you're trying to save into the filename must be global if you're going to call a static HFile.save('filename'). Generally we try to reduce globals to keep things more manageable.
But if you want to write procedural code, then it's ok.
IMO static methods are not useful for the purpose you've described is common at your workplace.
Disadvantages of this method:
- what's the point of creating an object that represents a file in order essentially just to call one method on it?
- cannot use interface-based polymorphism
To answer your question, here are some cases where I would use a static method:
- a utility method that does something related to the functionality of the class, but not to any one object. Perhaps it takes an array of objects and compares them. Perhaps it does some generic data manipulation (conversions, etc.).
- where you need to do class-related stuff with class variables
- where you want to implement a singleton design pattern