Все последующие обсуждения являются результатом моего опыта разработчика. Нет жестких правил, и вполне возможно, что вы не согласитесь со мной или я передумаю в будущем. Это нормально, я думаю, что это часть непрерывного процесса обучения.
Есть два основных подхода к вашей проблеме.
Явная
Идея здесь определяет интерфейс, имеющий методы, разработанные для определенной c цели. Вот пример:
public interface IOrderRepository
{
IEnumerable<Order> GetOrdersForCustomer(Guid customerId);
}
Здесь у вас есть метод GetOrdersForCustomer
, который позволяет вам получить все заказы, сделанные одним указанным c клиентом. Все ясно.
Обратите внимание, что в этом случае способ использования элемента интерфейса очевиден , и это действительно ценно.
Гибкость
Если вы хотите быть более гибкими и предоставить потребителям интерфейса больше свободы, вы можете определить интерфейс следующим образом:
public interface IOrderRepository
{
IEnumerable<Order> GetOrders(Func<Order, bool> filterCondition);
}
Здесь вы предоставили потребителям способ внедрения универсальных c критериев фильтра. по которому они хотят фильтровать заказы. Это гораздо более гибко, но менее явно.
Пример использования следующий:
Guid clientId = // some client id that you have in scope
var clientOrders = _repository.GetOrders(order => order.ClientId == clientId);
Что делать?
Это зависит от ваших конкретных c сценарий, нет правильного и неправильного ответа.
Я предпочитаю быть явным, потому что мне нравится строго придерживаться принципа единой ответственности , когда я пишу код, и я думаю, что явность - это дополнительная ценность (ваш код легче понять и проверить).
Последнее замечание: что мне делать, если мне действительно нужен динамический c запрос?
Существуют несколько расширенных вариантов использования, когда требуется полностью динамический c запрос. Когда я говорю динамический запрос c, я имею в виду запрос, который полностью определяется во время выполнения. Типичным примером является сценарий, в котором пользователю разрешено предоставлять какие-либо критерии (критерии сортировки, критерии упорядочения и т. Д.) Во время выполнения, например, в виде простого текста. Эти случаи на самом деле редки, и, по моему мнению, по возможности, лучше их избегать.
Если вам действительно нужен такой уровень гибкости, то go использует библиотеку, управляемую деревом выражений, например эту , которая позволяет вам выполнять текстовые динамические c запросы.
В этом случае я бы определил интерфейс, предназначенный для выполнения предоставленного пользователем динамического c запроса, с именем, которое четко определяет его назначение. Возможен следующий дизайн:
public class DynamicQuery
{
public string FilterCriteria { get; set; } // user provided filter criteria in the form of a string containing code
public string OrderCriteria { get; set; } // user provided order criteria in the form of a string containing code
}
public interface IProductDynamicQueryExecutor
{
IEnumerable<Product> GetProducts(DynamicQuery query);
}
Способ использования этого интерфейса довольно понятен для клиентского кода.
Опять же, я бы избегал любого вида интерфейса общего назначения, предназначенного для выполнения динамических c запросов на любом типе объекта (как вы можете видеть, этот интерфейс строго разработан для случая использования продуктов).
Вообще говоря, если не требуется абсолютно , я предпочитаю избегать любой необязательной абстракции в моем коде (в этом случае может возникнуть соблазн определить общий интерфейс c, где тип сущности выражается как универсальный параметр типа c, что-то вроде IDynamicQueryExecutor<TEntity>
).
Единственной идеей общего назначения в приведенном выше коде является класс с именем DynamicQuery
, потому что мне кажется разумным, что любой динамический c запрос состоит из какого-то критерия фильтрации и некоторого рода критериев сортировки , Как правило, помните, что немного дублирования кода лучше, чем слишком много абстракции в вашем коде . Опять же, я думаю, что явный и простой в написании код неоценим . Один из моих любимых преподавателей однажды сказал, что преждевременная абстракция убивает проекты , и я полностью с ним согласен.
Точный способ, которым потребительский код может express критерий, зависит от выбранной библиотеки для конкретной реализации, но, вообще говоря, это код, выраженный в каком-то мета-языке, таком как этот:
string filterCriteria = "Name = \"Contoso LTD\" AND City = \"Gotham City\"";