在Domain-Driven-Design中定义应用程序层

时间:2010-04-16 03:41:45

标签: design-patterns architecture domain-driven-design

我对DDD有疑问。我正在构建一个学习DDD的应用程序,我有一个关于分层的问题。我有一个这样的应用程序:

UI图层调用=> 应用层 - > 域层 - > 数据库

以下是代码外观的一个小例子:

//****************UI LAYER************************
//Uses Ioc to get the service from the factory.
//This factory would be in the MyApp.Infrastructure.dll
IImplementationFactory factory = new ImplementationFactory();

//Interface and implementation for Shopping Cart service would be in MyApp.ApplicationLayer.dll
    IShoppingCartService service = factory.GetImplementationFactory<IShoppingCartService>();

    //This is the UI layer,
    //Calling into Application Layer
    //to get the shopping cart for a user.

    //Interface for IShoppingCart would be in MyApp.ApplicationLayer.dll
    //and implementation for IShoppingCart would be in MyApp.Model.
    IShoppingCart shoppingCart = service.GetShoppingCartByUserName(userName);

    //Show shopping cart information.
    //For example, items bought, price, taxes..etc
    ...

    //Pressed Purchase button, so even for when
    //button is pressed.
    //Uses Ioc to get the service from the factory again.
    IImplementationFactory factory = new ImplementationFactory();
    IShoppingCartService service = factory.GetImplementationFactory<IShoppingCartService>();
    service.Purchase(shoppingCart);


    //**********************Application Layer**********************
    public class ShoppingCartService : IShoppingCartService
    {
       public IShoppingCart GetShoppingCartByUserName(string userName)
       {
           //Uses Ioc to get the service from the factory.
           //This factory would be in the MyApp.Infrastructure.dll
           IImplementationFactory factory = new ImplementationFactory();

           //Interface for repository would be in MyApp.Infrastructure.dll
           //but implementation would by in MyApp.Model.dll
           IShoppingCartRepository repository = factory.GetImplementationFactory<IShoppingCartRepository>();

           IShoppingCart shoppingCart = repository.GetShoppingCartByUserName(username);
           //Do shopping cart logic like calculating taxes and stuff
           //I would put these in services but not sure?
           ...

           return shoppingCart;
       }

       public void Purchase(IShoppingCart shoppingCart)
       {
            //Do Purchase logic and calling out to repository
            ...
       }
    }

我似乎把我的大多数业务规则都放在服务而不是模型中,我不确定这是否正确? 另外,我不完全确定我的铺设是否正确?我在正确的地方有合适的部件吗?我的模型也应该离开我的域模型吗?一般来说,我是按照DDD这样做的吗?

谢谢!

4 个答案:

答案 0 :(得分:3)

当你问

  

我的模特应该离开我的域名模型吗?

我想说,如果可能的话,你应该努力避免在一个程序中的不同对象集之间来回移动数据。这样做会导致你经历大量乏味的编写很多无聊和容易出错的代码,你将拥有一组冗余的DTO对象,它们必须镜像你的域对象,你也可以从你的方法中获得更少的里程数写,因为它们只在DTO或域对象上运行。总而言之,这是非常痛苦的,并没有取得多大成就。我尝试在整个应用程序中传递一组域对象。

(这并不意味着没有你真正需要在不同的对象集之间移动数据的情况,例如在构建反腐败层时。如果不是绝对的话,不要去寻找麻烦必要的。)

至于

IShoppingCart shoppingCart = repository.GetShoppingCartByUserName(username);
//Do shopping cart logic like calculating taxes and stuff
//I would put these in services but not sure?

域驱动设计的目标之一是尝试将业务逻辑与基础架构代码分开。无论你怎么能弄清楚如何仅使用域对象进行计算,最好进入域模型,在那里你可以编写不涉及数据库的测试。我希望让服务提取域对象的聚合,然后在域对象中进行业务逻辑计算,然后让服务保存计算在域对象中带来的状态更改。

答案 1 :(得分:2)

当服务(应用程序层)仅公开域对象上的命令而不是对象本身时,DDD最有效。

在你的例子中,我将在内部创建一个像Purchase(strng productName,int quantity)这样的服务方法 从Repository获取ShoppingCart(不必在这里使用界面) 从Repository获取Product(按名称) 并致电cart.AddProduct(产品,数量)

不是,将产品添加到购物车,计算总金额,总重量或其他商业资料的业务逻辑被封装在模式中。

答案 2 :(得分:1)

域对象和服务之间应该有一个薄层用于操作域对象(Eric Evans推荐)。此对象名通常以“Manager”结尾。例如PurchaseManager或类似的。连接不同域对象(用户,购买,地址......)的所有逻辑都在此对象中。

  • 服务电话Manager.GetSomething()
  • Manager从不同的存储库获取数据,执行业务逻辑并返回结果
  • 管理员返回结果但从不返回域对象本身!如果您有名为User的域对象,您应该坚持使用您发明的命名约定并将User映射到UserDataContract或类似。不要公开域对象。这是额外的工作,但您不应该将您的域模型与UI结合。
  • 很多时候,域对象都有方法来做一些业务逻辑

答案 3 :(得分:0)

关于你的问题:

  

&#34;我似乎把我的大多数业务规则都放在服务中而不是   模型,我不确定这是否正确?&#34;

如果业务规则不访问其他资源(数据库,服务,域对象),则可以在域对象本身中拥有该规则。如果它确实访问了其他资源,那么您应该将它们放在域服务中。