5

I am consuming a web service in C# using REST APIs. So, I have created a wrapper classes for each endpoint. It seems like a good idea to implement the wrapper using statics. This makes code look much cleaner. For example, consuming a method on Albums endpoint looks as follows.

List<Album> albums = AlbumsEndpoint.GetAllAlbums();
Album myAlbum = AlbumsEndpoint.GetAlbum("myAlbumId");

On the other hand consuming this API using an instance would look awkward.

List<Album> albums = new AlbumsEndpoint().GetAllAlbums();
Album myAlbum = new AlbumsEndpoint().GetAlbum("myAlbumId");

Still, I see a lot of SDKs using this pattern. (Here's one example.) What's the point of creating an instance here? Wouldn't it be a singleton? Doesn't that add an overhead of keeping that instance alive?
So, is it okay to use statics throughout? What do I miss by not using instance classes?

1
  • Instantiating a class only to call a single method seem ugly to me. What you really want is a stand-alone function, but since C# does not support that, a static method is the simplest way to achieve the same. So I disagree with the other answer.
    – JacquesB
    Jul 21, 2016 at 16:45

3 Answers 3

10

Static class methods are basically global functions, and are considered a bad idea in OO design. The reason why they are considered bad is hard to see in a simple code example where you are just comparing the difference between calling the same method on an instance or on the class itself.

But when you get into slightly more complicated design global functions become a real problem.

Take for example the code

albums = new AlbumsEndpoint().GetAllAlbums();

vs

albums = AlbumsEndpoint.GetAllAlbums();

These might look very similar but in the top one you have an object, and in the second you have a global function (AlbumsEndpoint.GetAllAlbums() is a global function, it really has nothing to do with a class, GetAllAlbums() could hang off any class it wouldn't matter)

The object code can be replaced with a line like this

albums = myEndpointInstance.GetAllAlbums();

And this will still work. What is myEndpointInstance? It is any object that satisfies the contact that it provides a GetAllAlbums method. This object can come from some where else, it doesn't have to be instantiated in here in the code (see Dependency Injection). This gives you flexibility, because the code doesn't care what type of object myEndpointInstance is just so long as it provides the expected interface.

You might come along tomorrow and write a completely new Endpoint object that works completely differently, and pass that object in here in this code. The code above won't care because it doesn't care how the endpoint object works, it only cares that it does work. And you don't touch any where else that was using the different older object. That all just keeps working fine.

Now see what happens when you instead of using an object use a global function. You have tied this code to the global function AlbumsEndpoint.GetAllAlbums(). Tomorrow you want to change how the code works here, but you don't want to change how it works anywhere else. So you have to create a new global function, you then have to change the code in your method to use the new global function.

Not so bad in a small code base that rarely changes. Headache in larger code that needs to be maintained.

If you use objects you have the flexibility that objects give you in that objects will act on any message they understand, the code calling the object doesn't need to know what exactly the object is. If you instead use global functions you tie the calling of the function to a very specific implementation of that function, and changing that after the fact can be hard and introduce bugs. This is after all one of the primary advantage of Object Orientated design in the first place

7
  • Sorry but that's not what's going on. Album is non static entity class that holds information about album. The static API wrapper is called Albums - plural. I've edited the question to make this more clear. So, comparison is between static wrapper and instance wrapper.
    – akshay2000
    Jul 21, 2016 at 15:37
  • Same principle applies. The "class" shouldn't be doing anything other than creating an instance. That instance should do the actual work. Why would be come clearer if you tried to use AlbumsEndpoint to get albums from two different servers in the same code base. I assume you are hard coding all the URL information for the API in the class itself. Imagine if you had to change that on the fly, how would you do it? If you are just creating static procedural functions and hanging them off class names you aren't leveraging the power of objects at all Jul 21, 2016 at 16:28
  • So are you suggesting that using instance is better? What are the benefits. The way I see it, instances are supposed to have some info unique to that object. (For example, color of a car.) But in case of endpoint, there's literally zero state information to be preserved. So, all the instances ever created will be same. Why bother with instances, then?
    – akshay2000
    Jul 21, 2016 at 16:34
  • 1
    The benefits are polymorphism. The rest of your code shouldn't care how you get albums. But when you hard code a global function (which is basically what a class static is, there is no reason why it has to live on Albums, it could live anywhere), you have coupled what happens to a specific implementation of how it happens. This greatly reduces flexibility, which you will realize as soon as you try and change how the system gets Albums and find that everything breaks. You are essentially no longer doing OO programming, you are doing procedural programming. Jul 21, 2016 at 17:04
  • I've updated the question to hopefully explain better. Jul 22, 2016 at 10:39
4

Frameworks/SDK's probably use instantance methods because it makes dependency injection possible, which is not really the case for static methods. However, if you don't use DI, a static method is the simplest way. KISS.

1
  • 1
    Can you add more details (maybe a use case) on how DI would be applicable here?
    – akshay2000
    Jul 21, 2016 at 17:06
2

Whenever I create a non-trivial static method to use, I always end up regretting it because of how difficult it can be to test. Especially if you use it all over the codebase.

Example of a perfectly fine static method:

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

It also doesn't have any required dependencies.

But when you have something like this:

public static User getCurrentUser() {
    var auth = SecurityContextHolder.getContext().getAuthentication();
    if (!auth.isAuthenticated()) {
        throw new UserNotLoggedInException();
    }

    return ((User) auth.getPrincipal());
}

It just becomes a nightmare. I used this static method way too liberally and while it did make the code look "cleaner", it made testing much more difficult. If you can, I would suggest using DI whenever possible.

Disclaimer: I have little experience in SWE, so take this answer with a grain of salt. Just sharing my two cents.

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.