4

我有以下基本实体:

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它将整个产品列表作为参数,并返回一个过滤的产品列表。或者也许它应该直接进入调用类的方法?

或者是其他东西?对此的最佳做法是什么?

4

4 回答 4

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));

当然,这是一个简单且可能多余的示例,但如果您添加 And、Or 和 Not(请参阅链接),您可以将复杂的业务逻辑构建到规范变量中。

于 2012-05-29T14:09:59.507 回答
2

如果“廉价产品”的概念是一流的领域概念并且必须以普遍存在的语言引入,我会做的是与领域专家一起看看。

如果是这种情况,Steve 的规范解决方案会以一种优雅的方式解决您的问题。

如果廉价不重要或定义不明确(例如,如果廉价阈值在整个应用程序中有所不同),我不会费心为其创建特定实体,只需在调用代码时使用相关标准过滤 Basket.Products .

于 2012-05-29T15:41:12.827 回答
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);  
    }  
}  
于 2012-05-29T13:44:15.290 回答
0

是的,我建议将您的 DTO 与业务逻辑分开。我喜欢将数据对象视为与数据访问、业务和 UI 层完全分离的层。如果你有一个更通用的 ProductBusiness 类,我建议你把它放在那里,除非有一个单独的过滤器类真的很有用。

于 2012-05-29T13:41:05.907 回答