1

I have an object with has two properties: Text and Type.

To avoid hard-coding the Types, I put them in the database, so they can be added to in future. At the moment the types are URL, Username and ID.

However, I now want to run a Utility method to clean up the object's Text field based on which Type the object is (e.g. add 'http://' if its a URL).

Is there a way to do this in the Utilities class without hard-coding the types in a switch statement/if else block.

switch (type)
{
    case 1:
        TidyUrl();
    case 2:
        TidyUsername();
    case 3:
        TidyID();
    default:
        break;
}

In this example I'm hardcoding the IDs from the database ('Type' table), which can never be a good thing!

Is there a better way to do this?

finoutlook
  • 2,523
  • 5
  • 29
  • 43
  • Whether I use interfaces and factories, enumerators or method names in the database doesn't seem to get around the if/else logic which will be needed somewhere to say which is which, and that's the part which I can't find a way to avoid hard-coding. – finoutlook Sep 26 '11 at 11:06

5 Answers5

4

You can use an enum to help with readability.

enum MyTypes
{
 URL = 1,
 UserName = 2,
 Id = 3,
}

switch (myType)
{
    case MyTypes.URL:
        TidyUrl();
    case MyTypes.UserName:
        TidyUsername();
    case MyTypes.Id:
        TidyID();
    default:
        break;
}

This enum will need to be kept coordinated with the database.

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • Yeah I've done this in the past, but it seems to just put the same problem (keeping ids in sync) in a different place. – finoutlook Sep 26 '11 at 10:57
  • @finoutlook - But at least it is _clear_ where that place is. From my experience, you _have_ to have a mapping _somewhere_ in the codebase. – Oded Sep 26 '11 at 10:59
  • Yeah I agree its clearer (and could group other mappings together e.g. in an Enumerators class) and better than being spread through the code. – finoutlook Sep 26 '11 at 11:08
3

One way is to use polymorphism. You'd have separate classes for each of your "types" and they'd implement a common interface (or have a common base class) with a method like Tidy, where each would do its own logic.

Jordão
  • 55,340
  • 13
  • 112
  • 144
  • 2
    And a factory method that will look up the type coded in the DB and create a new object of that type. Possibly using a `switch` statement ;) – Oded Sep 26 '11 at 10:58
  • @Oded - Exactly, no matter what option, I'm going to have to link my code directly to what's in the DB – finoutlook Sep 26 '11 at 11:00
  • 1
    Yes, that's true; but this technique avoids the proliferation of those switch statements. You'll only need _one_. Or _none_, if you prefer to use reflection... – Jordão Sep 26 '11 at 11:05
2

Traditionally this is handled using a common interface, and dynamically constructing a concrete implementation to do the actual work.

for example:

public interface ITidy
{
   string Tidy(string input);
}

then the implementations

public class UrlTidy : ITidy
{
    public string Tidy(string input)
    {
        // do whatever you need to the url
    }
}

And so on for the other types of tidying. Now you need a way of instantiating the right concrete class (UrlTidy, IdTidy etc) from the type you are looking at. One way to do this might be to put the class name in the database along side the type, and use reflection to instantiate the right implementation of ITidy. Another wat would be to have a Factory class which uses some other method to instantiate the right ITidy based on type.

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • Putting the class or method name in the database is like hardcoding the other way around. This might be preferable though. – finoutlook Sep 26 '11 at 11:03
  • @finoutlook - no its nothing like hardcoding. It's the complete opposite, allowing you to extend the types dynamically (assuming you release a new assembly containing that class). It's akin to a plug-in system allowing you to extend the abilities of your app without releasing the entirity of the software. – Jamiec Sep 26 '11 at 11:07
  • Yeah I see the advantage of it being in the database. Makes maintenance far easier and you're right it can be changed dynamically. – finoutlook Sep 26 '11 at 11:22
0

You could use enum Type but their constant values will have to determined at compile time. You can put a class invariance check in the enum to ensure that the are consistent with the database.

But how does having them in the database make it extendible?

Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
  • I think your question is good about why its extendible. There are a limited number of methods but some of the types in the database might share the same methods e.g. a new `UrlWithQuerystring` type might use the same `TidyUrl()` method. – finoutlook Sep 26 '11 at 11:13
  • If you are keen on not hard-coding the numbers then the solution I outline above should work nicely. Bonus points if you can make individual classes for each type, put the typeid and handler class in a database table and initialize the handlers objects and store them in a registry at start-up. – Miserable Variable Sep 26 '11 at 11:34
0

As Oded said, use an enum:

public enum Types
{
    Type1 = 1,
    Type2 = 2,
    Type3 = 3
}

You can then cast your type variable to the enum, having the integers map to the database IDs:

switch ((Types)type)
{
    case Types.Type1:
        break;
    case Types.Type2:
        break;
    ...
}

Hope that helps

SneakAttaack
  • 179
  • 12