Normally, to use a class, what we do is: We declare the class and its members, instantiate the class into a variable, and then use the class members through that variable. One of the reasons why we work like this is with regard to the data of the object. If a class defines data to store, then we need different objects to save the data of the different instances of the class. Thus, if we have a Person class, and we want to have a set of people, each with their data, we need to instantiate the Person class several times. However, what happens when we need functionality which does not depend on an instance of a class? Well, for that we can use static.
When we declare something as static, it means that its functionality is not related to an instance of a class. For example, a static method is one that can be used without the need for an instance of the class. While a static class is one that cannot be instantiated, and all its members must be static.
There are several use cases for static, one of the most common is to declare general utility methods which do not depend on an instance of the class that hosts the method. When we talk about utility methods, we mean common functionality which we will want to use from different places in our application.
For example, suppose we want to calculate the age of a person, where could we store this functionality? One option is in the Person class, however, if we want to calculate the age of other things, then it would make sense to place such functionality in a separate class. Since the age calculation does not have to depend on an instance of a class, we can place it in a static class:
As we can see, the DateUtilities class is a static class, therefore, it cannot be instantiated. To use any of its methods we do it through its name:
We will use this class from the Person class to calculate the age of a person. We can do this with both a property and a method, I will do it with a property:
As we can see, the Age property is read-only and uses the static DateUtilities class to calculate the person’s age.
When to use static classes?
So, can we always use static classes when we want to group functionalities that do not depend on instances?
Unfortunately, there are certain disadvantages to consider when we use static. One of the most important in my opinion is that you cannot use interfaces in static classes. This has a domino effect of consequences that can make your software less maintainable, since we cannot code against abstractions. This means that we cannot exchange implementations at runtime, which causes a tight coupling between our classes.
Since static classes can not be instantiated, that means we cannot use dependency injection. Later we will talk about dependency injection and coupling, but basically this is a technique that allows us to have a loosely coupled systems, where different parts of our software can evolve with some freedom without having to affect other parts.
It is important to take these disadvantages into account when deciding whether or not to use a static class. In my opinion, static classes are appropriate for relatively unchanging, universal functionality that is not fundamental to our software. Since we need a context for analysis, suppose we are making software for a human resources department. Let’s analyze our example of age calculation based on this criterion:
- The calculation of age is a functionality that we do not need to vary, it could be said that it is something simple: It is only to count the number of years between a given date and the current date.
- Age calculation is universal, in the sense that we might want to use it in different places in the same way. Example: Calculation of the number of years a person has been working in the company.
- Age calculation is not essential for our software: Although important, calculating the number of years between two dates is not precisely the central axis of our application.
Based on our analysis we can conclude that it is appropriate to use a static class to place the age calculation functionality.
However, our analysis depends on the fact that our software is for automating Human Resources processes. What would happen if our software were related to animal care? Let’s analyze:
- The age calculation is a functionality we might want to change. Depending on the advances in biology, maybe variations are made in the formulas for calculating the age of animals
- Age calculation is not universal, depending on the animal in question and its characteristics, we may need a different formula for calculating its age.
- Age calculation is essential for our software, since the age of an animal tells us about its health and needs.
Therefore, we conclude that it would not be a good idea in the case of an animal care application to use a static class to place age calculation functionality.