У нас есть система доставки контента, которая предоставляет множество различных типов контента для устройств.
Все содержимое хранится в базе данных с contentID
и mediaTypeID
.
В этом примере допустим, что MediaType
может быть одним из этих 2, но на самом деле их гораздо больше.
Gif
MP3
Поскольку содержимое хранится в разных местах на основе медиатипа и требует отправки разных заголовков, это большой неприятный фрагмент старого кода, который по существу переключает каждый тип медиа и устанавливает правильные параметры. * Я хотел бы изменить это на более общую реализацию. Так вот, что у меня до сих пор в моем каркасе
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
}
}
Что все кажется разумным... Пока я не доберусь до класса менеджера.
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
}
Проблема в том, что мне все равно нужно инициализировать этот тип с помощью определенного IContentTypeDownloader для этого идентификатора MediaTypeID.
И я вернусь к квадрату 1, с ситуацией вроде
if(mediaTypeID == 1)
ContentManager<GifDownloader> cm = new ContentManager<GifDownloader>();
else if (mediaTypeID == 2)
ContentManager<MP3Downloader> cm = new ContentManager<MP3Downloader>();
и т.д...
Любая идея о том, как сделать это последнее решение общим на основе значения mediaTyepID
, которое выходит из базы данных
Я duno, если вы можете его создать дальше, чем то, что у вас уже есть.
Возможно, создав класс factory, который просто вернет вам правильный интерфейс, основанный на любом типе носителей, будет более удобным решением.
public static class MediaInterfaceFactory
{
public static IContentTypeDownloader Create(int mediaId)
{
switch (mediaId)
{
case 1:
return new GifDownloader();
case 2:
return new Mp3Downloader();
}
}
Я думаю, что вполне приемлемо иметь простой шаблон дизайна Factory. Конечно, вы можете сходить с ума и иметь словарь Enum, представляющий ваш тип контента как ключ и фактический тип как значение. И затем в вашем классе Factory возьмите Enum и используйте Activator.CreateInstance, чтобы вернуть правильный тип.
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);
}
вы можете использовать это с mediaId, конечно же, в словаре.
Думаю, я могу так поступить:
Определите атрибут, который вы размещаете на своих конкретных загрузчиках типов контента:
[MediaType (ID = 1)]
При запуске сканируйте свою сборку и настройте словарь типа contentID → экземпляр загрузчика типа контента, связанного с идентификатором (вы выяснили, что это с атрибутом)
Затем ваш код должен быть уменьшен до
downloader = dictionary[mediaType].Clone();
С помощью контейнера DI по вашему выбору вы можете заменить словарь и сканировать, например. Конфигурация, основанная на соглашениях.
Type t
используя Reflection, основываясь на имени MediaType, который вернулся из базы данных. например, "Gif" получит `Type t = Assembly.GetExecutingAssembly (). GetType (mediaTypeName +" Downloader ");", но не радость ...