views:

214

answers:

3

We have a content delivery system that delivers many different content types to devices. All the content is stored in a database with a contentID & mediaTypeID.

For this example lets assume the MediaType can be one of these 2 but in reality theres many more of them.

Gif
MP3

Because the content is stored in different places based on mediatype and requires different headers to be sent, theres a big nasty piece of legacy code that essentially switches on each mediatype and sets the correct parameters. *I'd like to change this into a more generic implementation. So heres what I've got so far in my wireframe

public interface IContentTypeDownloader
{
    MemoryStream GetContentStream();
    Dictionary<string, string> GetHeaderInfo();
}

public class GifDownloader : IContentTypeDownloader
{
    public MemoryStream GetContentStream(int contentID)
    {
        //Retrieve Specific Content gif
    }

    public Dictionary<string, string> GetHeaderInfo()
    {
        //Retrieve Header Info Specific To gifs
    }
}

public class MP3Downloader : IContentTypeDownloader
{
    public MemoryStream GetContentStream(int contentID)
    {
          //Retrieve Specific Content mp3
    }

    public Dictionary<string, string> GetHeaderInfo()
    {
        //Retrieve Header Info Specific To mp3s
    }
}

Which all seems sensible... Until I get to the Manager Class.

public class ContentManager<T> where T : IContentTypeDownloader
{
    public int ContentID { get; set; }

    public MemoryStream GetContent()
    {
        IContentTypeDownloader ictd = default(T);
        return ictd.GetContentStream(this.ContentID);
    }
    ... etc
}

The problem is, I still need to initialise this type with the specific IContentTypeDownloader for that mediaTypeID.

And I'm back to square 1, with a situation like

if(mediaTypeID == 1)
    ContentManager<GifDownloader> cm = new ContentManager<GifDownloader>();
else if (mediaTypeID == 2)
    ContentManager<MP3Downloader> cm = new ContentManager<MP3Downloader>();

etc...

Anyone any idea on how to make this last decision generic based on the value of the mediaTyepID that comes out of the Database

+1  A: 

I think I may go about this like that:

  • Define an attribute you place on your specific content type downloaders:

    [MediaType(ID = 1)]

  • Upon startup scan your assembly and set up a dictionary of style contentID -> instance of the content type downloader associated with the id (you figured that out with the attribute)

  • Have your content type downloaders some method like IContentTypeDownloader Clone();

Then your code should be reduced to

downloader = dictionary[mediaType].Clone();

With a DI Container of your choice you may be able to replace the dictionary and scanning with e.g. a convention-based configuration.

flq
+2  A: 

I duno if you can generify it any further than what you have already.

Perhaps creating a factory class which just returns you the correct Interface based on whatever media type would be a neater solution i.e.

public static class MediaInterfaceFactory
{
    public static IContentTypeDownloader Create(int mediaId)
    {
       switch (mediaId)
       {
            case 1:
                return new GifDownloader();
            case 2:
                return new Mp3Downloader();

    }
}
James
Or even apply a similar solution but to your ContentManager where the factory returns you a ContentManager based on the mediaId.
James
Thanks for the suggestions guys. Have gone with the factory method.At least everything is in one place, if it ever does become more dynamic I'll look at refactoring it more into a DB with an Activator to generate the class Types.
Eoin Campbell
+1  A: 

I think it is totally acceptable to have a simple Factory Design Pattern. Of course you can go really crazy and have a Dictionary of Enum representing you content type as key and the actual Type as value. And then in your factory class take in the Enum and use Activator.CreateInstance to return the right type.

public enum MediaTypes
        {
            GIF,
            MPEG
        }


Dictionary<Enum, Type> dictionary = new Dictionary<Enum, Type>() { { MediaTypes.GIF, typeof(GifDownloader) } };

public static IContentTypeDownloader Create(MediaTypes mediaType)
    {
      Type type= dictionary[mediaType];
      IContentTypeDownloader contentObject = Activator.CreateInstance(type);

    }

you can use this with mediaId's of course as well in the dictionary..

Stan R.