实现领域驱动

什么是领域驱动?

领域驱动设计 (domain-driver-design) 是有别于MVC开发模式的一种思想,它是面向对象编程的一种表现形式,请记住:领域驱动是一种思想,而不是技术!
领域驱动核心是通过对模型抽象出属性和行为进行开发。
如果没有数据库?

为什么使用领域驱动?

1、建立统一语言,为了团队更好的沟通。
2、通过模型来表达需求,模型是模块化、可扩展、易于维护的。
3、业务实现和技术实现隔离。
4、通过建模达到解耦的目的

领域驱动中的一些概念

1、统一语言
2、领域实体(聚合根)
在这里插入图片描述
3、值对象(value-object)
4、模型(失血模型、充血模型、胀血模型)
5、边界上下文
6、领域知识
7、领域事件

层级划分

常规分层结构图
1、表现层
2、应用服务层
3、领域层(领域实体和领域服务)
4、基础设施层(仓储、工具、rpc、第三方api)

通过一个 用例来展现领域驱动

一个登陆业务:
1、用户(User)输入账号(account)和密码(password)。
2、需要校验account和password正确性。
3、“7天未登陆” 或者 “更换设备”需要手机(phone)验证码(captha)校验。
4、登陆成功后做一些操作(比如:发个推送消息、做一条记录)

 public UserLoginInfoRespDto login(UserLoginReqDto userLoginReqDto) {
        User user = userService.doLogin(userLoginReqDto);
        userRepository.updateUserData(user);
        String token = authService.createToken(user.getUserId(), user.getUserData().getDeviceId());
        //查询更新后的用户信息
        UserLoginInfoRespDto userLoginInfoRespDto = userAssembler.assemblerUserLoginInfo(
                userService.getWithFormsAndNotNull(user.getUserId())
        );
        userLoginInfoRespDto.setLoginToken(token);
        domainEventPublisher.publish(new UpdateResourcesEvent(this,
                Lists.newArrayList(user.getUserData().getUserName()),
                userLoginInfoRespDto.getUserId(),
                ResourceModeType.LOGIN.getValue()));
        return userLoginInfoRespDto;
    }
 public User doLogin(UserLoginReqDto loginReqDto) {
        String userName = loginReqDto.getUserName();
        String deviceId = loginReqDto.getDeviceId();
        String captcha = loginReqDto.getCaptcha();
        String regChatId = baiduAIApiService.faceQuery(userName);
        if (StringUtil.isEmpty(regChatId)) {
            throw new BusinessException(ResponseStatus.USER_IS_NOT_REG);
        }
        User regUser = Optional.ofNullable(userRepository.getByChatId(regChatId))
                .orElseThrow(() -> new BusinessException(ResponseStatus.USER_IS_NOT_REG));
        regUser.validateNotLoginForLongTime();
        regUser.validateChangeDevice(deviceId,captcha);
        regUser.updateLoginData(loginReqDto);
        return regUser;
    }

让你的getter/setter丰满起来

领域驱动中,模型的getter/setter是可以具有逻辑的

public List<UserForm> getUserForms() {
        if (this.userForms == null) {
            if (this.userId == null) {
                this.userForms = new ArrayList<>();
            } else {
                this.userForms = SpringBeanUtils.getBean(IUserRepository.class)
                        .getForms(this.userId);
            }
        }
        return this.userForms;
    }

让应用层参与协调

应用层是很薄的一层,不包含任何逻辑,仅用于协调和发布命令

 public Object prePay(PayReqDto payReqDto) {
        Fund fund = new Fund(payReqDto);
        payBizFactory.handleBiz(fund);
        Object prePayResult = payTypeFactory.prePay(fund);
        //保存日志时保存为负数
        fund.setUserFund(-fund.getUserFund());
        fundRepository.add(fund);
        return prePayResult;
    }

领域实体和领域服务

整个domain层都是逻辑的封装,domain是独立的,不能被其他层侵入,持久化通过接口隔离。
何时使用领域服务?

  • 领域行为需要多个领域实体参与协作
  • 领域行为与状态无关
  • 领域行为需要与外部资源(尤其是DB)协作

面向资源库

把数据库(文件、nosql或者是其他持久化库)看作是一个集合,领域实体是其中的一个元素,整体持久化

    @Override
    public void add(User user) {
        UserDataEntity dataEntity = userConverter.convertUserDataEntityFromUser(user);
        userDataJpaRepo.save(dataEntity);
        user.setUserId(dataEntity.getUserId());

        UserInfoEntity infoEntity = userConverter.convertUserInfoFromUser(user);
        userInfoJpaRepo.save(infoEntity);

        UserAppendEntity appendEntity = new UserAppendEntity();
        appendEntity.setUserId(user.getUserId());
        appendEntity.setPhone(infoEntity.getPhone());
        if (dataEntity.getRegType() == RegisterType.WX.getValue()) {
            appendEntity.setPhone(dataEntity.getUserName());
        }
        userAppendJpaRepo.save(appendEntity);

        UserEngagementAwardEntity awardEntity = userConverter.convertEngagementAwardFromUser(user);
        userEngagementAwardJpaRepo.save(awardEntity);
    }

领域层隔离带来的问题

领域对象展示和持久化需要进行转换,Assembler 和 Translater

通过测试来快速验证模型

    @Test
    public void testLogin(){
        User user = userService.getWithFormsAndNotNull(68L);
        user.validateNotLoginForLongTime();
    }

领域驱动是银弹吗?

如果你只是做一个简单的CRUD系统,我并不推荐。用这个思想开发起来并不快,而且具有一定的门槛。
不要生搬硬套其中的概念,灵活运用。
领域驱动的乐趣在于领域划分、建模,应对复杂业务变化。

题外话

设计模式、微服务划分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值