Chr*_*s W 1 c# tagging domain-driven-design asp.net-mvc-3
我正在寻找为我所参与的项目添加可标记功能.该项目是3层(mvc3 - 域 - 存储库).
我需要添加标记此系统中各种对象的功能.因为标签可以附加到许多不同的聚合根,我最好将标签作为自己的根(域中的rep/ITagManager).
我的想法是让ITaggable界面类似于:
public interface ITaggable
{
bool SaveTags(IList<ITag> _tags);
bool SaveTag(ITag _tag);
IList<ITag> GetTags();
bool HasTag(IList<ITag> _tags);
bool HasTag(ITag _tag);
bool HasTag(string _tagName);
}
Run Code Online (Sandbox Code Playgroud)
我有一个想法,有一个ITagManager,它有方法来获取ITaggable对象并保存/加载附加到它们的标签(可能使用类似String.Concat(typeof(this),this.ID)来生成对象的唯一ID.实现ITaggable接口).现在有两种可能的路由,首先将任何实现ITaggable接口的对象传递到ITagManager本身,或者将Itaggable接口修改为如下所示:
public interface ITaggable
{
bool SaveTags(IList<ITag> _tags, ITagManager _tagManager);
bool SaveTag(ITag _tag, ITagManager _tagManager);
IList<ITag> GetTags(ITagManager _tagManager);
bool HasTag(IList<ITag> _tags, ITagManager _tagManager);
bool HasTag(ITag _tag, ITagManager _tagManager);
bool HasTag(string _tagName, ITagManager _tagManager);
}
Run Code Online (Sandbox Code Playgroud)
第一个解决方案可能是贫血模型的气味,但第二个解决方案看起来很混乱.我知道可以注入依赖关系,但我认为将它作为一个函数参数可以明确地说明发生了什么.或者将它注入对象会更好吗?
这些解决方案是否合适?
任何帮助/建议将不胜感激.
我不认为你的'ITagable'界面需要非常臃肿.此外,我不会将标签建模为聚合根,因为标签本身没有任何意义.
这是我们使用的界面:
public interface ITagable
{
IEnumerable<Tag> Tags { get; }
void Tag(Tag tag);
void Untag(Tag tag);
}
Run Code Online (Sandbox Code Playgroud)
如果需要,您在界面上的许多方法都可以轻松实现为扩展方法.
有时您无法处理域对象中的所有逻辑.这是域服务很有用的地方,也是我们用来处理'ITagable'实体上标签"处理"的地方:
public interface ITagService
{
void ProcessTags<TEntity>(TEntity entity, Func<IEnumerable<Tag>> featureTags,
string tagString) where TEntity : ITagable;
}
Run Code Online (Sandbox Code Playgroud)
请注意,我们传入'featureTags'列表.在博客示例中,这将是整个博客的标签列表,因为我们不想创建重复的标签.因此,"TagService"不执行任何类型的持久性,它只是在需要时创建新标记(在博客上),如果需要,则在实体上标记或取消标记:
public class TagService : ITagService
{
public void ProcessTags<TEntity>(TEntity entity,
Func<IEnumerable<Tag>> featureTagsFactory, string tagString) where TEntity : ITagable
{
var result = new List<Tag>();
// remove any leading/trailing spaces
tagString = tagString.Trim();
if (tagString.IsNotNullOrEmpty())
{
result.AddRange(from str in tagString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Where(t => t.Length > 1).Distinct()
join tag in featureTagsFactory() on (Slug)str equals tag.Slug into tags
from tag in tags.DefaultIfEmpty()
select tag ?? new Tag(str.Trim()));
}
// merge tags
foreach (var tag in entity.Tags.Except(result)) // remove unmatched tags
{
entity.Untag(tag);
}
foreach (var tag in result) // entity should check if already added
{
entity.Tag(tag);
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我们更新可标记实体(通常从我们的UI层传递逗号分隔的标记列表)时,我们执行以下操作:
// tags
if (command.TagString.IsNotNullOrEmpty())
{
tagService.ProcessTags(post, () => blog.Tags, command.TagString);
}
Run Code Online (Sandbox Code Playgroud)
在我的例子中,我们将所有标签映射到我们的父博客对象.您可能无法复制+粘贴此代码,但它应该让您了解如何处理实体上的标记处理.