2012-05-29 1 views
3

У меня есть следующие основные объекты:Куда должна следовать логика фильтрации коллекции в приложении, управляемом доменом?

public class Basket 
{ 
    public List<Product> Products {get;set;} 
} 

public class Product 
{ 
    public string Name {get;set;} 
    public decimal Price {get;set;} 
} 

И я хочу, чтобы получить список всех товаров в корзине, которые ниже фиксированной цене. Если логика для этого идти в Basket, например, так:

public class Basket 
{ 
    public List<Product> Products {get;set;} 
    public List<Product> CheapProducts 
    { 
     get { return Products.Where(p => p.Price < 5).ToList(); } 
    } 
} 

Или это пойти в классе обслуживания, ProductFilterer, который бы весь список продуктов в качестве параметра и будет возвращать отфильтрованный список продуктов , Или, может быть, нужно просто перейти к методу вызывающего класса?

Или что-то еще? Какова наилучшая практика для этого?

ответ

2

Что бы я сделал, это увидеть с экспертом в области, если понятие «дешевый продукт» является концепцией домена первого класса и должно быть представлено на вездесущем языке.

Если это так, решение спецификации Steve решит вашу проблему элегантным способом.

Если дешевизна несущественна или не так четко определена (например, если порог дешевизны варьируется в зависимости от приложения), я бы не стал создавать для него конкретный объект и просто фильтровать Basket.Products с соответствующими критериями, когда необходимых для вызова кода.

+0

+1 для крика. :) –

0

Да, я бы предложил сохранить ваш DTO отдельно от бизнес-логики. Мне нравится думать, что объекты данных являются полностью отдельным слоем из слоев доступа к данным, бизнеса и пользовательского интерфейса. Если бы у вас был более общий класс ProductBusiness, я бы порекомендовал просто разместить его там, если не очень полезно иметь отдельный класс фильтратора.

0

Ваш класс Basket не должен знать, как фильтровать напрямую, это правильно для того, чтобы он имел открытую функцию, которая позволяет ему возвращать результаты из ProductFilter, как вы предложили. То, как код должен выглядеть как-то так:

class ProductFilter 
{ 
    filterCheapProducts(Collection<Product> productsToFilter) 
    { 
     return Products.Where(p => p.Price < 5).ToList(); //I assume your code is correct 
    }  
} 

class Basket 
{ 
    Collection<Product> getCheapProducts() 
    { 
      return filter.filterCheapProducts(this.products); 
    } 
} 
2

Вы могли бы рассмотреть вопрос о поиске в Specification Pattern. Ссылка имеет хороший пример реализации, но, короче говоря, шаблон позволяет создавать сложные критерии выбора на основе простых предикатов (или спецификаций).

Быстрая (и неполный) реализация такой модели с помощью делегатов можно было бы сделать так:

public class Specification<T> 
{ 
    Func<T, bool> _spec; 
    public Specification(Func<T, bool> spec) 
    { 
     _spec = spec; 
    } 

    public bool IsSatisifedBy(T item) 
    { 
     return _spec(T); 
    } 
} 

// ... 

_cheapProductsSpecification = new Specification<Product>(p => p.Price < 5); 
var cheapProducts = Basket.Products.Where(p => _cheapProductsSpecification.IsSatifisifedBy(p)); 

Это, конечно, простой и, вероятно, излишним пример, но если вы добавите в И, Или, и не (см. Ссылку), вы можете построить сложную бизнес-логику в переменных спецификации.

+1

Просто добавив точку, Эванс предлагает вывести бизнес-правила, скрытые внутри методов, в объекты. Взгляните на [образец 'Cargo' e' Voyage'] (http://ptgmedia.pearsoncmg.com/images/chap1_0321125215/elementLinks/01fig10.gif). С помощью шаблона спецификации вы можете повторно использовать эти правила и повысить сплоченность: в вашем случае вы можете применить эти правила в своих хранилищах для образца. – lcardosobr

Смежные вопросы