集合过滤逻辑应该放在域驱动的应用程序中哪里?

时间:2012-05-29 13:36:05

标签: c# domain-driven-design

我有以下基本实体:

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 个答案:

答案 0 :(得分: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(请参阅链接),则可以将复杂的业务逻辑构建为规范变量。

答案 1 :(得分:2)

如果“廉价产品”的概念是一流的领域概念并且必须以无处不在的语言引入,那么我要做的就是与领域专家见面。

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

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

你的篮子类不应该知道如何直接过滤,它是正确的,它有一个暴露的功能,允许它按照你的建议从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);  
    }  
}