我正在寻找在社交网站上处理用户活动Feed的最合适方式。目前,我有几项活动可以出现在新闻Feed上,例如:
以下是我的域对象的简化版本:
public abstract class NewsItem : Entity, ITenantSpecific
{
public virtual Account Account { get; set; }
public virtual DateTime DateTime { get; set; }
// returns formatted news html string which gets
// overridden by inherted classes
public abstract string GetNewsHtml();
}
public class NewsItemJoiner : NewsItem
{
public virtual Account AccountJoined { get; set; }
public override string GetNewsHtml()
{
return "XXX has just joined our music network";
}
}
正如您所看到的那样,我有一个必须在每个名为GetNewsHtml
的活动上覆盖的属性。这并不理想,因为我不相信我的域应该负责生成我的HTML。
我考虑过为每种活动类型使用部分视图,并将NewsItem
基类传递给正确的类型。
但是我愿意接受建议。
答案 0 :(得分:0)
我有类似的问题,但订单类型不同。我决定在视图层(web / controllers)定义渲染,而不是域。你可以这样做:
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上使用lambda过滤器,Factory使用它来确定此接口实现是否适用于传递的(到GetRenderer( “某种条件”))条件。很多事情都是可能的。
如果您不想要IoC容器(ServiceLocator),可以使用NewsRendererFactory.GetRenderer中的简单switch()语句完成其工作。这将隔离单工厂方法中的逻辑,一旦准备就绪,您将能够使用真正的IoC轻松替换它。
更新:如何获得渲染器。
如果您不使用IoC,则执行类似
的操作 typeof(IRenderer<>).Assembly.GetTypes().Where(x =>
x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(IRenderer<>) &&
x.GetGenericArguments().FirstOrDefault() == requestedTypeArguments)
如果可以处理多个渲染器,则可以选择SingleOrDefault()或ToList()。