4

I was looking at a project and I found something very curious.

There is a static class that has a set of methods, where each method makes a call to a remote server.

The template looks kind of like this:

public static class DAI

    public static ResponseObject ExecStatement(string db, string sql)
    {
         { ... }
    }

    public static DataSetResponseObject GetDataSet(string db, string sql)
    {
         { ... }
    }

    public static DataTableResponseObject GetDataTable(string db, string sql)
    {
         { ... }
    }
}

But no where in the project makes a call to this class. Instead, it makes a call to an non-static class container.

public class ExecSP : IExecSP
{
    string _db;
    public ExecSP(string db)
    {
        _db = db;
    }

    public ResponseObject OutputAsResponseObject(string sql)
    {
         return DAI.ExecStatement(_db, sql);
    }

    public ResponseObject OutputAsDataSet(string sql)
    {
         return DAI.GetDataSet(_db, sql);
    }

    public ResponseObject OutputAsDataTable(string sql)
    {
         return DAI.GetDataTable(_db, sql);
    }
}

Now, the only two things I see as an advantage is that the nomenclature is more clear when wrapped up in a non-static container, and that there are less parameters to pass around.

But I'm wondering if this is a good idea by design to wrap up static class with non-static? What are some of the other reasons if there are any? Because I assumed that creating a static and making calls to it would be okay. But this project has made it a deliberate point to wrap up all static class; and I'm not sure why.

sksallaj
  • 3,872
  • 3
  • 37
  • 58
  • 9
    First thing to understand - there's no such thing as a "static object" or a "non-static object". There are static methods, static classes, static variables etc - but not static objects. The design you've discussed does sound odd. – Jon Skeet Dec 30 '13 at 21:52
  • Thanks for the heads up! I just made the edit – sksallaj Dec 30 '13 at 21:54
  • 2
    If the original authors of the classes are still present, it would be a good idea to ask them why they did it that way. – Jon Skeet Dec 30 '13 at 21:55
  • Sadly this has been around for 4 years, and since then, the tradition is to go with this approach. No one really gave me any reasons to why we do it. In fact, looking around online, people make mention of having a static class implement an interface, and I think this might be related? – sksallaj Dec 30 '13 at 22:00
  • Well a static class *can't* implement an interface... but I see no reason for the static class to start with. – Jon Skeet Dec 30 '13 at 22:07
  • Do you think I could perhaps start a prototype project, convert the static class into a singleton as mentioned by one of the answerers below? I really want to remove this approach entirely if there are no signicant advantages. I have the time to do it too. – sksallaj Dec 30 '13 at 22:10
  • It's not clear to me why it would be a singleton. Just move the contents of the static methods to become instance methods of the "normal" class... – Jon Skeet Dec 30 '13 at 23:02

5 Answers5

8

The most common reason I've done something like this in the past is if the static methods are provided by a third-party library (i.e. I didn't write it), but I don't want to write code that takes a direct dependency on that library. In that case, I'll write my own class and have it take the direct dependency instead.

Assuming I use an interface (or something similar like in your example), then if I decide down the road that I want to use a different library, I can write another class that implements the same interface and swap out the concrete class at runtime (using something like Dependency Injection).

Brian Ball
  • 12,268
  • 3
  • 40
  • 51
1

Looks to me like they are trying to make the object injectable in order to make your code easier to test and to modify later.

check this post: Why does one use dependency injection?

Community
  • 1
  • 1
Caleb
  • 1,088
  • 7
  • 7
0

Personally I would never do this, what I would do instead is use a .NET dependency injection framework like Ninject or Unity in order to inject the necessary references into objects as they're being created. There are many advantages to doing this...for starters you can create your singleton objects without actually having to use static members and you have much more control over their life cycle. If you want to do unit testing (and you should) then it is trivial to replace your singleton with a mocked object, and if you decide later on that maybe a singleton isn't the best design choice then it's trivial to inject an object that is scoped to something else such as the main parent view model etc. The project you're looking at is probably using that intermediate class to enable some of the things I'm talking about, but it'll never be as flexible or clean as doing proper dependency injection.

Mark Feldman
  • 15,731
  • 3
  • 31
  • 58
  • So are you saying to transform my static class into a singleton? then use dependency injection? – sksallaj Dec 30 '13 at 22:04
  • Almost...I'm saying transform your static class into a non-static class and then use the dependency injection framework to give it singleton scope. This is effectively the same as making the class a singleton but with an important exception: neither the class itself or any of the other code that references it know it's a singleton. It is the job of the DI framework to make it one and to provide a reference to the one instance of it whenever anything asks for it. That way you can easily change it to something else later on if and when you need to without breaking a whole lot of other code. – Mark Feldman Dec 30 '13 at 22:11
  • 1
    The world isn't always this sunshiny. Sometimes we need to utilize 3rd party code that wasn't designed so nicely. This facade can go a long way toward breaking dependencies on a static class. – RubberDuck May 07 '16 at 12:17
0

It's a standard pattern. - Wrap a more complicated set of methods to hide their complexity, such as a set of methods which only return errors via thrown exceptions. - Handle errors, exceptions, etc. in the wrapper methods - Make the methods static to prevent multiplication of derived methods like executeQueryByInt, executeQueryByLong, executeQueryByString, ... - Limit the propagation of references to the SQL handling framework code to only the wrapped methods - important Have a single place to document how to call, errors, special cases, bug workarounds when using the third party static library

For unit testing, your unit tests should implement a short wrapper class which only passes through calls to the static class.

There's no need to add another layer of complexity, no matter how simple, to just fit an arbitrary pattern or cloud your code. Your production code should not implement extra code just if that code is used in unit tests.

It's common to wrap a library or nuget package in a project by itself so that a multi-solution project does not have dozens of package references to a third party package.

Odd how Angular has the concept of a barrel, yet .net core has none; and you get into Nuget Package h*ll once the number of projects is more than 10 and the solution is older than 2 years.

Having restructured 1,000,000+ line .net solutions multiple times, static methods and static classes make the code easier to move around in the larger context. What best practices scale well at smaller projects do not scale well for 1,000,000+ line systems. It's a different approach than found in toy projects and short blog entries. It's about being able to see what code is called and where the code is called so that refactoring, simplification is easier.

BobS
  • 1
-1

The added class ExecSP is serving no benefit. Both methods pass in a db string and a sql string. I imagine the db string is some sort of connection string to a database instance and the sql is the raw sql string to be executed by that instance. In this case might as well call the DAI directly, there is no reason for the wrapper class.

From a design prosepctive, this is tight coupling. We probably want to abtract away the database (IDatabase) by creating an instance and then running a command against the abstraction instead of passing around the connection string/sql statement.

Psudeo Code:

IDatabase dbInstance =  new DatabaseCreator(db);
dbInstance.Execute(sql); 

Then it doesn't matter if the database is SQL Server, Oracle, etc.

Abstraction helps with testing. For example, in a unit test project I can write my own IDatabase implementation that doesn't even use a database. I am not sure how you would test this without an actual database instance. If I write my own test instance, I can remove that external dependency.

Jon Raynor
  • 3,804
  • 6
  • 29
  • 43
  • The `ExecSP` class is doing exactly what you are describing in your Psudeo Code. (I assume that the users of the class are using the interface `IExecSP`) The benefit is that you only have to pass in the `db` string on construction. So you don't need to give it to every method call. Then if you inject the object into other classes, they don't need to know anything other than the sql they want to execute. – Caleb Dec 31 '13 at 00:37
  • Good point, I see it, IExecSP is the interface. Still don't like passing around the database string. – Jon Raynor Dec 31 '13 at 15:53