开始使用TDD和DDD

时间:2009-09-25 09:57:46

标签: c# tdd domain-driven-design repository-pattern

我刚读完Eric Evans的“领域驱动设计:解决软件核心的复杂性”,我正在尝试编写我的第一个以域为中心的应用程序(在C#中)。

我们的服务台将使用该应用程序来跟踪向用户分配的计算机。

我已经草拟了一个简单的类图来反映域的一部分。它看起来像这样......

Class diagram showing two classes: Owner and Computer. There is a one-way associate between Computer and Owner named 'Allocate to' http://www.freeimagehosting.net/uploads/183dd57031.jpg

我还确定了我的第一个功能(将计算机分配给用户)并为其编写了测试...

[Test]
public void AllocateToUser()
{
    var user = new Owner("user1");
    var computer = new Computer("computer1");

    computer.Allocate(user);

    Assert.AreEqual(user.Username, computer.AllocatedTo.Username);
}

最后,我编写了代码以使测试通过。

public class Computer
{
    public Computer(string name)
    {
        Name = name;
    }

    public string Name
    { get; private set; }

    public Owner AllocatedTo
    { get; private set; }

    public void Allocate(Owner owner)
    {
        AllocatedTo = owner;
    }
}

public class Owner
{
    public Owner(string username)
    {
        Username = username;
    }

    public string Username
    { get; private set; }
}

到目前为止,很好(我认为)。

然而,显然这些都没有解决持久性问题。我想我需要为Computer引入一个存储库类。也许是这样的事情:

public class ComputerRepository
{
    public void Store(Computer computer)
    {
        //Some persistence logic here (possibly using NHibernate?)
    }
}

现在我被卡住了。如何确保对计算机分配的用户所做的更改传递到存储库?

我似乎有以下选择:

  1. 修改Computer类的Allocate方法的实现,以实例化ComputerRepositry的实例并调用Store方法。

  2. 创建接口IComputerRepository;修改Computer的构造函数,要求提供实现IComputerRepository的类的实例。在Allocate方法中,针对此注入的实例调用Store。

  3. 创建一个服务(AllocationService),它将包含对Allocate和Store的调用。

  4. 将resposibility传递给客户端,强制调用代码执行两个步骤:

    • 在计算机类的实例上调用分配
    • 实例化ComputerRepository的实例并调用Store。
  5. 这些似乎都不令人满意:

    1. 很难测试,因为我将直接在Computer类中实例化存储库。

    2. 通过使用依赖注入来避免此问题。但是它仍然很难看,因为我每次想要实例化计算机时都需要传递一些IComputerRepository实例。

    3. 过于程序化,无法将行为封装在域实体类中。

    4. 看起来很难看。

    5. 我该怎么办?

1 个答案:

答案 0 :(得分:5)

通常我会将行为和持久性视为两个不同的问题并分别进行测试。

Domain对象应该不知道存储库的存在(尽管显然不是相反)。

我们在这种情况下所做的是创建一个Controller(或服务),负责从其存储库加载适当的对象,调用对象上的行为,然后调用存储库来保存更新。

然后,您可以使用Mock存储库测试控制器,以检查控制器是否使用更新的对象调用存储库。