Veikedo

Untitled

Oct 31st, 2016
271
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.19 KB | None | 0 0
  1. Это из цикла "Проблемный шаблон 'репозиторий'". Нет чёткого и удовлетворяющего всем решения.
  2. Попробую написать вкратце.
  3.  
  4. 1. Некоторый плюют на всё и экспозят (от слова expose) наружу IQueryable из контракта репозитория:
  5. interface IRepository<T> {
  6. IQueryable<T> Query();
  7. }
  8.  
  9. Здесь проблема в том, что бизнес-логика (БЛ) может оказаться размазанной по всему проекту.
  10.  
  11. В качестве маскирования размазанности иногда выносят БЛ в методы расширения для IQueryable.
  12. public static IQueryable<Customer> WhereIsActive(this IQueryable<Customer> q){
  13. return q.Where(c => c.Orders.Any() && c.LastLogonDate.Days < 365);
  14. }
  15.  
  16. В принципе, можно и в отдельные правила в отдельном классе выносить:
  17.  
  18. class CustomerBL {
  19. Expression<Func<Customer, bool>> IsActive = c => c.Orders.Any() && c.LastLogonDate.Days < 365;
  20. }
  21.  
  22. 2. Можно выносить методы прямо в контракт репозитория:
  23.  
  24. interface ICustomerRepository : IRepository<Customer> {
  25. GetActive();
  26. }
  27.  
  28. Здесь проблема в том, что у вас может быть over9000 методов в вашем репозитории.
  29. Это очень напрягает. Тяжело поддерживать и ответственность размазанна.
  30.  
  31. 3. Паттерн Спецификация
  32.  
  33. interface ISpecification<T> {
  34. bool IsSatisfied(T entity);
  35. }
  36.  
  37. interface IRepository<T> {
  38. IReadOnlyList<T> GetAll(IReadOnlyList<ISpecification<T>> specs);
  39. }
  40.  
  41. class IsActiveSpecification : ISpecification<Customer>{
  42. public bool IsSatisfied(Customer c) {
  43. return c.Orders.Any() && c.LastLogonDate.Days < 365);
  44. }
  45. }
  46.  
  47. 4. DDD. Выносите вашу БЛ в модель
  48. public class Customer {
  49. public DateTime LastLogonDate { get; protected set; }
  50. public IReadOnlyList<Order> Orders { get; protected set; }
  51.  
  52. public bool IsActive() {
  53. return c.Orders.Any() && c.LastLogonDate.Days < 365);
  54. }
  55. }
  56.  
  57. 5. Посмотрите в сторону CQRS, MessagePattern/"Pub/Sub"
  58. Можно комбинировать с предыдущими пунктами. Сложнее, но гибче.
  59. Позволит избавиться от проблем в пункте 2 (но, естественно, наплодит другие).
  60.  
  61. public class ActiveCustomersQuery {
  62. }
  63.  
  64. public class CustomerQueryHandler {
  65. public IReadOnlyList<Customer> Handle<ActiveCustomersQuery>(ActiveCustomersQuery query){
  66. return _repository.Where(x => x.IsActive());
  67. }
  68. }
  69. Как я уже сказал, Pub/Sub можно использовать и без DDD.
  70.  
  71. 6. Почитайте блоги Александра Бындю (http://blog.byndyu.ru/), Сергея Теплякова (http://sergeyteplyakov.blogspot.ru/) и Максима Аршинова (https://habrahabr.ru/users/marshinov/topics/)
  72. У них много статей про эту проблему.
Advertisement
Add Comment
Please, Sign In to add comment