У меня похожая проблема, но с разными типами заказов. Я решил определить рендеринг на уровне представления (веб / контроллеры), а не на домене. Вы можете сделать это так:
public interface IRenderer<T> where T: NewsItem
{
string Render(T item);
}
public class NewsItemJoinerRenderer: IRenderer<NewsItemJoiner>
{
public string Render(T item)
{
return "XXX has just joined our music network";
}
}
public class NewsRendererFactory
{
public IRenderer<T> GetRenderer<T>()
{
return ServiceLocator.GetInstance<IRenderer<T>>();
}
}
Затем вы можете передать NewsRendererFactory контроллеру. Возможно, есть способ избежать ServiceLocator, но пока я не могу сказать.
Обратите внимание, что это делает вашу архитектуру настраиваемой и подключаемой при необходимости.
Вы можете определить дополнительные интерфейсы, связанные с рендерингом, добавить дополнительные свойства в IRenderer - например, PartialName и т. Д., Или иметь лямбда-фильтры в IRenderer, которые Фабрика использует, чтобы решить, применима ли эта реализация интерфейса для переданного (для GetRenderer ( «некоторое состояние»)) состояние. Многое возможно.
Если вам не нужны контейнеры IoC (ServiceLocator), вы можете выполнить свою работу с помощью простого оператора switch () внутри NewsRendererFactory.GetRenderer. Это изолирует логику внутри метода единой фабрики, и вы сможете легко заменить ее истинным IoC, как только будете готовы.
Обновление: как получить рендереры.
Если вы не используете IoC, вы делаете что-то вроде
typeof(IRenderer<>).Assembly.GetTypes().Where(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IRenderer<>) &&
x.GetGenericArguments().FirstOrDefault() == requestedTypeArguments)
Затем вы можете выбрать SingleOrDefault () или ToList (), если вы можете обрабатывать несколько визуализаторов.