views:

114

answers:

5

Hi,

I have a table which houses two entities, StaticProgram and DynamicProgram. There is one column in that table called ProgramType which determines if a program is of type "Static" or "Dynamic". Though these two entities are stored in one table (I am guessing because the primitive fields for Static and Dynamic programs are exactly the same) but from a business point of view these are two VERY different entities.

So, I created two classes StaticProgram and DynamicProgram. However, I donot want to create two seperate Data Access Classes because it is going to be the exact same code replicated twice. I tried creating a "Program" class as base class and inherited StaticProgram and DynamicProgram classes but down casting is not supported so I can't return a "Program" object from the data access class and cast it to "StaticProgram" class etc.

So, what are my options? Can I create an IProgram interface and have StaticProgram and DynamicProgram implement that interface and have my Data Access class return IProgram? Or what about making the Data Access method a Generic method (if this is possible and is a recommended approach I will need some help as I do not have much expreience with generics)? Any other suggestions?

I would appreciate your help!!

Update: The data access method is static indeed:

public static class ProgramDataMapper
{
    public static Program GetProgram(int programID)
    {
        Program p = new Program();
        // database stuff
        p.Name = reader["Name"].ToString();
        ...
        return p;
    }
}

Base class looks like:

public class Program
{
    // Properties

    public static Program GetProgram(int programID)
     {
            return ProgramDataMapper.GetProgram(programID);
     }
}

Finally the derived class:

public class DynamicProgram : Program
{
    // Additional Business Related Properties

    public new static DynamicProgram GetProgram(int programID)
        {
            return (DynamicProgram)Program.GetProgram(programID);
        }
}

This compiles just fine but I get a Cannot cast "Program" to "DynamicProgram" exception at runtime.

Also, what about a generic method? Unless I am off the mark here but, theoratically, can we not do something like:

public static IProgram GetProgram<T>(int programID) where T : IProgram
{
    IProgram program;
    Type returnType = typeof(T);
    if(returnType is StaticProgram)
    {
        program = new StaticProgram();
    }
    else if(returnType = DynamicProgram)
    {
        program = new DynamicProgram();
    }

    //if (T is StaticProgram)
        //{
        //  returnValue = new StaticProgram();
        //}
        //else if (T is DynamicProgram)
        //{
        //  returnValue = new DynamicProgram();
        //}

    // db operations
}

Of course the code above doesn't work. I get "The given expression is never of the provided type (StaticProgram) type."

+1  A: 

IMO your data entities should reflect your db model and your business entities should reflect your business model

I think it is perfectly fine to have a single entity in the data model that corresponds to several business entities. In your case, I'd go for one independent data entity and 2 business entities inheriting from a common ancestor but would avoid any relation between data and business entities.

vc 74
A: 

I tried creating a "Program" class as base class and inherited StaticProgram and DynamicProgram classes but down casting is not supported so I can't return a "Program" object from the data access class and cast it to "StaticProgram" class etc.

Weird, because exactly that should work:

public Program GetProgram(){
    if(someDataCoulumn.Equals("Static")) {
        return new StaticProgram(...);
    } else {
         return new DynamicProgram(...);
    }
}

public void Caller(){
    var p = GetProgram();
    var sp = p as StaticProgram;
    if(sp != null) {
       DoSomethingWithStaticProgram(sp);
    } else {
       var dp = p as DynamicProgram;
       if(dp != null){
           DoSomethingWithDynamicProgram(dp);
       } else {
           throw new SomeBusinessException("Program is neither Static not Dynamic, instead it's " + p.GetType().FullName);
       }
    }

}
Michael Stum
A: 

The thing to examine is which one of your approaches does not violate LSP (Liskov Substitution Principle) . Since you said it yourself they are two very different things the use of an inheritance model will not truly work here. The redundant code could be stripped out to a third class that would expose itself through static methods or you could have a reference to this 'helper' class inside each of your two program objects.

Woot4Moo
A: 

How about having a static class to do all your DataAccess?

Vivek
A: 

How about this:

public static class ProgramDataMapper
{
    // Change to a generic here to manufacture any class deriving from Program.
    public static T GetProgram<T>(int programID)
        where T : Program, new()
    {
        T p = new T();
        // database stuff
        p.Name = reader["Name"].ToString();
        ...
        return p;
    }
}

public abstract class Program
{
    // Properties

    // Manufacture a concrete class that derives from Program
    public new static T GetProgram<T>(int programID)
        where T : Program, new()
    {
        return ProgramDataMapper.GetProgram<T>(programID);
    }
}

public class DynamicProgram : Program
{
    // Additional Business Related Properties

    public new static DynamicProgram GetProgram(int programID)
    {
        // Specifically manufacture a DynamicProgram
        return Program.GetProgram<DynamicProgram>(programID);
    }
}

Philosophically, perhaps an interface might be more suited, but for getting what you have to work with somewhat minimal effort, this should do the trick.

Your posted code will not cast to a DynamicProgram because you specifically constructed a Program object in the ProgramDataMapper. While a DynamicProgram "is a" Program, the reverse is not true. In the code I have provided here, using generics, a DynamicProgram is constructed instead of just a Program. Using generics also removes the need for casting at all in the DynamicProgram.GetProgram method.

Matt Hamsmith
This is precisely what I was after! Thank you so much!
Robert
@Robert - Glad to help.
Matt Hamsmith