young.han

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

写这篇文章主要是之前三篇对DDD的介绍算是自己学习的一次试水,也希望能够有更多的人能帮我发现其中的问题。昨天继续阅读了DDD书,发现了自己之前的例子存在了一些问题,早上也和园友进行了一些讨论。最后整理出此文,还记得第一篇用户注册是怎么做的吗?再次回顾一下,但也有一点变化,为了更好的符合DDD, 这次将应用代码写在了Application层中。

先贴上领域内的核心代码

public class User
{
    public User(string name, string password)
    {
        this.Name = name;
        this.Password = password;
        this.Id = Guid.NewGuid().ToString();
    }

    public string Id { get; private set; }
    public string Name { get; private set; }
    public string Password { get; private set; }
}

public interface IUserRepository
{
    void Add(User user);
}

public interface IEncryptionService
{
    string Encrypt(string password);
}

public class UserFactory
{
    private readonly IEncryptionService _encryptionService;
    public UserFactory(IEncryptionService encryptionService)
    {
        this._encryptionService = encryptionService;
    }

    public User Create(string loginId, string password)
    {
        return new User(loginId, _encryptionService.Encrypt(password));
    }
}

public interface IRegisterUserService
{
    User RegisterNewUser(string name, string password);
}

再贴上Application的代码

public class UserService
{
    private readonly IRegisterUserService _registerUserService;
    private readonly IUserRepository _userRepository;

    public void Register(string name, string password)
    {
        User user = _registerUserService.RegisterNewUser(name, password);

        _userRepository.Add(user);
    }
}

你有没有看到现在与之前的变化,是不是有点看不懂了?是的,这次我完全抛弃了domain service技术实现,这也是我昨天看原著和今天早上讨论出的结果,为什么会是这样?首先我个人的理解是domain service和repository一样,强调他们能做的是什么,而不是我怎么做的,之前我也有过把精力集中放在repository的技术实现上,最后发现它对于我思考领域没有什么太大帮助,当然不是说不重要,而是忽略了DDD的重点,同理domain service也一样,它也是强调能为我们做什么,只要定义的接口能够表达业务目的就可以了。所以用户注册这个例子,业务规则是要求注册的过程用户名必须唯一,domain service能够很好的反应这个过程,这个过程不一定要你就立即去解决它。刚刚我还想到由domain service提供一个接口来检查用户名是否唯一(如ValidateService.CheckUserNameIsUnique(user)),然后由application层先创建一个user,然后再检查用户名,看起来似乎蛮合理的,在领域内做了一些封装,但是这样却将领域知识暴露给了应用层或UI,很显然方向错了。

所以我会考虑将domain service和repository的实现放在基础设施层中,那么在基础设施层中domain service如果需要用到repository也是可以的。这样就不会有之前蟋蟀兄的疑惑了

对IRegisterUserService作一个简单的实现演示

class RegisterUserService : IRegisterUserService
{
    private readonly UserFactory _userFactory;
    private readonly UserRepository _userRepository;

    public User RegisterNewUser(string name, string password)
    {
        if (_userRepository.IsNameExist(name)) {
            throw new Exception("用户名已存在");
        }

        return _userFactory.Create(name, password);
    }
}

也有人提出创建出来的用户是否合法也可以由工厂来保证,这里我想说也是可以的,但是我个人不推荐,这样工厂可能还需要其他一些知识,尽管在领域内部,这是可控的,但是我觉得他已经不纯洁了,工厂就是创建复杂对象用的,不需要掺杂着其他东西,而且它也不能表达用户注册这个过程。

 

总结

在学习DDD的过程中你会发现实现一个功能方式可能会更多,但是什么是合理的,可能一时并不能找到答案,甚至也迷糊。如果你在尝试DDD过程中也出现了错误,没有关系,每个人都会范,从错到对都会有一个过程,但是我们要勇于承认并纠正自己的错误,没什么大不了的。如果你体会到DDD的好处会显得很兴奋,想用在具体项目上,我想建议还是缓一缓吧,虽然它是一把瑞士军刀或者中国军队的军用铲,但是用好它还是需要先了解到你能够很轻松的运用。

 

 

补充

经过一番讨论,对于IRegisterUserService是不是需要定义成接口还是希望读者能有自己的思考,还有对于IRegisterUserService的实现我考虑是在基础设施层实现,这是一个错误的方向,应该是在领域内,因为他的知识范围就在领域内,而不是在领域外,至此我自己也更加清晰了。

posted on 2014-08-07 11:24  young.han  阅读(2795)  评论(19编辑  收藏  举报