Я реализую шаблон фильтра (критериев), и я не уверен, что лучший подход заключается в создании универсального TypeOfCriteria.
Чтобы дать некоторый контекст, часть системы фильтрации является специфической, например, у меня есть фильтр EmailAddressContains внутри папки UserCriteria. Пользовательский класс является абстрактным, и есть несколько различных пользовательских типов, унаследованных от этого базового класса, например AdminUser и FullControlUser. Другие части системы имеют похожие деревья наследования. Сначала я реализовал определенные критерии TypeOf, такие как TypeOfAdminUser, но вскоре решил, что могу сделать это более общим.
Я придумал три подхода, и я не уверен, какой из них "лучший". Или, может быть, есть другой подход, о котором я еще не подумал.
Подход 1
public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}
public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
private readonly Type _type;
public TypeOfCriteria(Type type)
{
_type = type;
}
public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return from T entity in entities
where entity.GetType().Equals(_type)
select entity;
}
}
Использование:
ICriteria<User> criteria = new TypeOfCriteria<User>(typeof(AdminUser));
admins = criteria.MeetCriteria(users);
Подход 2
public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}
public class TypeOfCriteria<T, TResult> : ICriteria<T>
where T : BaseEntity
where TResult : BaseEntity
{
public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}
Использование:
ICriteria<User> criteria = new TypeOfCriteria<User, AdminUser>();
admins = criteria.MeetCriteria(users);
Подход 3
public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities);
}
public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
public IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}
Использование:
ICriteria<User> criteria = new TypeOfCriteria<User>();
admins = criteria.MeetCriteria<AdminUser>(users);
Плюсы и минусы
Подход 1 больше всего напоминает мои другие классы Criteria, где я передаю фактические критерии в конструкторе (new EmailAddressContains (". Com")).
Реализация подхода 2 в MeetCriteria выглядит чище. Я не уверен в производительности, похоже, она может быть быстрее, но это не совсем тот показатель, о котором я беспокоюсь для этого проекта.
Мне нравится Подход 3 меньше всего, потому что он требует, чтобы я изменил интерфейс.