新来的技术总监,把DDD落地的那叫一个高级优雅!

构建PHP域驱动设计(DDD)示例应用 本文还有配套的精品资源,点击获取 简介:PHP领域对象与示例应用 1. 领域驱动设计概念 领域驱动设计(Domain-Driven Design,简称DDD)是软件开发中的一种方法论,它强调将软件开发的关注点集中于业务领域,使设计模型能够更加紧密地反映业务规则和流程。DDD的核心思想是,在复杂的软件项目中,业务逻辑和领域知识往往比技术实现更加重要。因此,设计... 阅读详情

前言

我们在日常开发中,经常听到DDD,那么DDD到底是什么呢? 我之前也看过一些网络上的文章,都是写了一大堆的文字,比较羞涩难懂.本文打算跟大家聊聊DDD.让大家看清楚它的模样~

1. 什么是DDD

DDD(Domain-Driven Design,领域驱动设计)是一种通过聚焦业务领域来构建复杂系统的软件开发方法,核心思想是将代码结构与业务领域的实际需求深度结合。

一句话简单概括就是:用代码还原业务本质,而非实现功能。

  • 对于传统开发,就是对着PRD需求文档,写if-else(数据库怎么设计,代码就怎么写).
  • 而对于DDD,拉着业务方画领域模型,代码就是业务的镜子(业务怎么变,代码就怎么调)

2. 传统的开发模式,一个简单的注册例子

其实这些概念上的东西,看完过会,还是很容易忘记对吧~ 我们来看一个代码例子吧~

假设我们做一个用户注册的例子,业务规则如下:

  • 用户名必须唯一
  • 密码必须满足复杂度要求
  • 注册后需记录日志

传统模式,于是可以快速写出以下代码:

@Controller
public class UserController {
    public void register(String username, String password) {
        // 校验密码
        // 检查用户名
        // 保存数据库
        // 记录日志
        // 所有逻辑混在一起
    }
}

有些伙伴说,哪有所有代码混合在controller,肯定要分层的呀,比如分controller、service、dao层. 于是写出类似这样的代码:

// Service层:仅有流程控制,业务规则散落在各处
public class UserService {
    public void register(User user) {
        // 校验规则1:写在工具类里
        ValidationUtil.checkPassword(user.getPassword()); 
        // 校验规则2:通过注解实现
        if (userRepository.exists(user)) { ... }
        // 数据直接传递到DAO
        userDao.save(user); 
    }
}

你还别说,这快代码,其实流程已经比较清晰了~ 有些伙伴,满怀激动地说,已经分层了,代码已经很优雅清晰了,这就是DDD了吧.

3. 分层就是DDD了吗?

答案是,NO!

以上代码虽然分层了,代码结构划分了,但是它还不是DDD.

其实对于传统的分层的那块代码,User对象仅是数据载体(贫血模型),业务逻辑被拆解到外部了.对于DDD,其实一些逻辑,可以内聚到领域User对象中的. 如密码规则的校验.

对于这个注册的例子, DDD的正确姿势(充血模型)如下:

// 领域实体:业务逻辑内聚
public class User {
    public User(String username, String password) {
        // 密码规则内聚到构造函数
        if (!isValidPassword(password)) { 
            throw new InvalidPasswordException();
        }
        this.username = username;
        this.password = encrypt(password);
    }

    // 密码复杂度校验是实体的职责
    private boolean isValidPassword(String password) { ... }
}

其实把校验密码的下沉到User 领域实体对象里了.专业点说法,就是业务规则被封装在领域对象内部,对象不再只是“数据袋子”。

3. DDD的关键设计

所以,DDD 就是把一些逻辑下沉到领域对象中?

不全对~

其实处了分层,DDD的关键设计,体现在以下模式深化业务表达:

  • 聚合根
  • 领域服务 vs 应用服务
  • 领域事件

3.1 聚合根(Aggregate Root)

  • 场景:用户(User)和收货地址(Address)关联
  • 传统方式:在Service中分别管理User和Address
  • DDD方式:将User作为聚合根,控制Address的增删
public class User {
    private List<Address> addresses;

    // 添加地址的逻辑由聚合根控制
    public void addAddress(Address address) {
        if (addresses.size() >= 5) {
            throw new AddressLimitExceededException();
        }
        addresses.add(address);
    }
}	

3.2 领域服务 vs 应用服务

  • 领域服务:处理跨多个实体的业务逻辑(如转账涉及两个账户)
  • 应用服务:协调流程(如调用领域服务+发送消息)
// 领域服务:处理核心业务逻辑
public class TransferService {
    public void transfer(Account from, Account to, Money amount) {
        from.debit(amount); // 账户扣款逻辑内聚在Account实体
        to.credit(amount);
    }
}

// 应用服务:编排流程,不包含业务规则
public class BankingAppService {
    public void executeTransfer(Long fromId, Long toId, BigDecimal amount) {
        Account from = accountRepository.findById(fromId);
        Account to = accountRepository.findById(toId);
        transferService.transfer(from, to, new Money(amount));
        messageQueue.send(new TransferEvent(...)); // 基础设施操作

领域事件(Domain Events)

  • 用事件显式表达业务变化
  • 例:用户注册成功后触发UserRegisteredEvent
public class User {
    public void register() {
        // ...注册逻辑
        this.events.add(new UserRegisteredEvent(this.id)); // 记录领域事件
    }
}

4. 传统开发和DDD的区别

简单总结一下传统开发和DDD的区别~

维度

传统开发

DDD

业务逻辑归属

散落在Service、Util、Controller

内聚在领域实体/领域服务

模型作用

数据载体(贫血模型)

携带行为的业务模型(充血模型)

| 技术实现影响 | 数据库表驱动设计 |业务需求驱动表结构设计 |

5. 电商下单的DDD例子

为了方便大家理解,再给大家来个DDD的案例.给大家解解渴、润润喉

假设有个需求:

用户下单需实现:校验库存、用优惠券、计算实付金额、生成订单。

  1. 传统写法(贫血模型):
/**
 * 
 * 公众号:捡田螺的小男孩
 **/
// Service层:大杂烩式下单
public class OrderService {
    @Autowired private InventoryDAO inventoryDAO;
    @Autowired private CouponDAO couponDAO;
    
    public Order createOrder(Long userId, List<ItemDTO> items, Long couponId) {
        // 1. 校验库存(散落在Service)
        for (ItemDTO item : items) {
            Integer stock = inventoryDAO.getStock(item.getSkuId());
            if (item.getQuantity() > stock) {
                throw new RuntimeException("库存不足");
            }
        }
        
        // 2. 计算总价
        BigDecimal total = items.stream()
                .map(i -> i.getPrice().multiply(i.getQuantity()))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        
        // 3. 应用优惠券(规则写在工具类)
        if (couponId != null) {
            Coupon coupon = couponDAO.getById(couponId);
            total = CouponUtil.applyCoupon(coupon, total); // 优惠逻辑隐藏在Util
        }
        
        // 4. 保存订单(纯数据操作)
        Order order = new Order();
        order.setUserId(userId);
        order.setTotalAmount(total);
        orderDAO.save(order);
        return order;
    }
}

传统方式存在的问题:

  • 库存校验、优惠计算散落在Service、Util、DAO
  • Order对象只是数据载体(贫血),业务规则无人认领
  • 改需求时,需在Service层“考古”
  1. DDD写法(充血模型):业务逻辑内聚到领域
/**
 * 
 * 更多干货,关注公众号:捡田螺的小男孩
 **/
// 聚合根:Order(承载核心逻辑)
public class Order {
    private List<OrderItem> items;
    private Coupon coupon;
    private Money totalAmount;

    // 构造函数内聚业务逻辑
    public Order(User user, List<OrderItem> items, Coupon coupon) {
        // 1. 校验库存(领域规则内聚)
        items.forEach(item -> item.checkStock());
        
        // 2. 计算总价(业务逻辑在值对象)
        this.totalAmount = items.stream()
                .map(OrderItem::subtotal)
                .reduce(Money.ZERO, Money::add);
        
        // 3. 应用优惠券(规则在实体内部)
        if (coupon != null) {
            validateCoupon(coupon, user); // 优惠券使用规则内聚
            this.totalAmount = coupon.applyDiscount(this.totalAmount);
        }
    }

    // 优惠券校验逻辑(业务归属清晰)
    private void validateCoupon(Coupon coupon, User user) {
        if (!coupon.isValid() || !coupon.isApplicable(user)) {
            throw new InvalidCouponException();
        }
    }
}

// 领域服务:协调下单流程
public class OrderService {
    public Order createOrder(User user, List<Item> items, Coupon coupon) {
        Order order = new Order(user, convertItems(items), coupon);
        orderRepository.save(order);
        domainEventPublisher.publish(new OrderCreatedEvent(order)); // 领域事件
        return order;
    }
}

改为DDD后的优点:

  • 库存校验:封装在OrderItem值对象中
  • 优惠券规则:内聚在Order实体内部方法
  • 计算逻辑:由Money值对象保证精度
  • 业务变化时,只改领域对象

假设产品又出了个新需求:优惠券需满足“订单满100减20”,且仅限新用户使用。

传统开发的方式影响了Service层、Util类,因为需要修改

1. 修改CouponUtil.applyCoupon()逻辑
2. 在Service层添加新用户校验

而DDD 只影响了领域层,因为只需要修改:

仅修改Order.validateCoupon()方法	

6. 什么场景该用DDD?

其实,是不是什么场景,都要使用DDD呢? 不是的,那就是小题大作啦~

  • ✅ 业务复杂(如电商、金融、ERP)
  • ✅ 需求频繁变更(90%的互联网业务)
  • ❌ 简单CRUD(管理后台、数据报表)

我觉得这句话有点道理:

当你发现修改业务规则时,只需调整领域层代码,而无需改动Controller或DAO,这才是DDD真正落地。

让代码和业务长成连体婴,改需求不再是程序员的噩梦 !!!

最后

一直坚持原创不易,大家给个三连支持一下哈. 如果你觉得本文有不对的地方,可以在评论区留言讨论哈~

USB-Type-C PCB布局布线设计规范 USB Type-C连接器有24个引脚。图1和图2分别显示了USB Type-C插座和插头的插针。母头/母座公头/插头可以很明显看出,插口内的Pin功能相对于中心对称。公头插入母头,无论正反插,引脚功能都完美契合。而且电源VBUS/GND都拥有4个Pin,最大支持5A电流,在保证高速数据传输的同时也提高了电流承载能力。表 1 和表 2 分别汇总了在 USB Type-C 型插座和插头上所使用的信号列表。 阅读详情

相关推荐

从CAD到完美网格:HyperMesh几何清理全流程指南(2023最新版)

本文详细介绍了2023最新版HyperMesh在几何清理和网格划分方面的全流程操作指南。从CAD导入、几何修复到中面提取和网格生成,系统性地分享了实战验证的解决方案,帮助工程师高效处理复杂几何体,提升有限元模型质量。特别针对汽车和航空航天领域的常见问题,提供了智能化工具和优化技巧。

weixin_29306011的博客 226

《领域驱动设计之php实现》- 仓储【转载】

为了与领域对象交互,你需要保留对它的引用。达到这个目标的途径之一就是通过创建器(creation)。或者你可以遍历关联。在面向对象程序中,对象具有与其他对象的链接(引用),这使它们易于遍历,从而有助于模型的表达能力。但这有一点很重要:你需要一种机制来检索第一个对象:聚合根。 仓储作为存储位置,其检索到的对象以与存储对象完全相同的状态返回。在领域驱动设计中,每个聚合类型通常都有一个唯一的关联存储库,用于持久化和检索需求。但是,在需要共享一个聚合对象层次结构的情况下,这些类型可能共享一个存储库。 只要你从仓储中

tiway的博客 564

Qt·DBus快速入门

DBus快速入门

m0_64560763的博客 2273

DDD 概念理解-理论篇

领域驱动设计(Domain Driven Design,DDD),DDD为我们提供了一种架构设计方法,既面向业务,又面向技术,从业务需求到领域建模,从领域服务到技术转化,强调开发人员与领域专家协同。DDD的核心思想是业务与技术相结合的一种过程,既强调业务的理解,又强调应用领域建模方法的使用。DDD本质上是面向对象分析的扩展和延伸,它基于面向对象分析技术进行了分层规划,同时对其中的核心概念和划分做了详细的指引。(理解是更深层次、全面的面相对象思维)

哎幽的成长 2245

cesium加载天地图、OSM、谷歌底图

以上示例是加载矢量底图,若要加载影像或者其他只需要更换相应的url,在WebMapTileServiceImageryProvider中还要更改layer参数。url中’‘vec_w’,一些其他风格,基于CRAT渲染,两种方法效果差别不大。有两种方法加载天地图分别是。对应投影样式,具体可看。还要谷歌的一些卫星底图。

qq_44897914的博客 3000

在MCUXpresso上通过J-link烧写KW45

背景: KW45B是nxp 的ble npi产品,其使用的IDE为MCUXpressso或者IAR,MCUXpressso有一些bug,但是由于MCUXpressso阅读查找代码相对IAR容易,所以我经常使用的MCUXpressso进行开发。当然IAR也有其优势,比如编译、烧写速度相对MCUXpressso更快,是比较通用的一个平台,而MCUXpressso是NXP独有的。 Kw45有两种烧写方式,一是使用MCUlink,二是使用Jlink。NXP ble 产品线提供的IDE资料里有最新的15.0版本的

weixin_41889258的博客 2859

领域驱动设计(DDD)初见面(附示例代码)

最近在重新关注微服务与Service Mesh的实践(后续我们系统来讲),随便关注了下领域驱动设计(DDD)。本文主要整理对领域驱动设计(DDD)初步了解,并提供了PHP的领域驱动设计(DDD)实践参考代码案例,希望能对大家有所帮助。

小马过河R的博客 1526

【26美赛A题】2026美赛数学建模(MCM/ICM)思路解析及代码分享

本文介绍了2026年美赛数学建模A题的解题思路与方法。A题通常属于连续型系统问题,重点在于构建可解释的机理模型,通过将现实机制转化为动态方程进行仿真预测。文章提出了通用建模路线,包括机理抽象、模型假设、动态建模、参数识别、系统仿真和情景预测六个阶段。专栏将提供从机理到方程的系统建模思路、参数标定方法、Python/Matlab实现代码以及高分论文模板。内容适合参加2026美赛A题、偏重物理/工程建模方向的参赛队伍,旨在提升机理建模能力。后续将更新完整题解和源码。

一键难忘的博客 2009

Laravel领域驱动设计(DDD)实战指南

Laravel领域驱动设计(DDD)实战指南 1. 项目目录结构及介绍 领域驱动设计在Laravel框架中的应用——laravel-domain-driven-design,简化了DDD实践过程。以下是核心的目录结构及其功能介绍: . ├── app # 主应用程序目录,包括业务逻辑的主要部分 │ ├── Domain # 领域层,...

gitblog_00242的博客 443

汽车行业新能源汽车数据爬虫:抓取新能源汽车数据,分析市场发展和技术创新

在汽车行业,新能源汽车市场的发展和技术创新是当前的热点话题。通过抓取新能源汽车的数据,我们可以深入了解市场趋势、消费者需求以及技术创新的方向。本文将详细介绍如何使用 Python 爬虫技术抓取新能源汽车数据,并对数据进行分析和可视化展示。

u014481728的博客 1144

基于Simulink进行步进电机的重复控制仿真建模

目的:通过引入一个周期延迟环节来补偿系统的周期性误差,从而提高系统对周期性参考信号或扰动的跟踪性能。方法内部模型原理:在控制器中嵌入一个与周期性信号相关的模型(例如周期延迟环节),以实现对周期性误差的零稳态误差控制。滤波器设计:为了避免高频噪声放大,通常会在重复控制器中加入低通滤波器。优势对周期性信号具有良好的跟踪性能。不需要精确的数学模型即可实现高性能控制。挑战:需要合理设计重复控制器的参数以避免系统不稳定。

MHD0815的博客 382

DDD+中台+微服务,yyds

随着业务的发展,每个产品都需要对应数量的开发者作为支撑,但在长期的协作中,我们发现开发团队都会遇到一些普遍难点:构建速度慢、开发测试周期长、协作困难等。在快速的业务迭代中,各团队的开发人...

架构师小秘圈 468

华为OD机考双机位C卷 - 虚拟理财游戏(Java & Python& JS & C/C++ & GO )

华为OD机考双机位C卷 - 虚拟理财游戏(OD上机考试双机位C卷)。提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。

算法大师! 668

程序员职场跃迁指南:从技术骨干到技术领袖的进阶之路

在当今快速变化的技术行业,程序员的职业发展远不止于编写代码。本文将系统性地拆解程序员职场晋升的完整路径,从初级开发到CTO的每个阶段需要掌握的核心能力,并提供可落地的成长策略。

as_asdf的博客 811

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

避免35岁现象,我给技术人的建议永远是架构师!

随着业务的发展,每个产品都需要对应数量的开发者作为支撑,但在长期的协作中,我们发现开发团队都会遇到一些普遍难点:构建速度慢、开发测试周期长、协作困难等。在快速的业务迭代中,各团队的开发人...

weixin_45583158的博客 151

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

程序员成长系列:从业务、技术到思维体系

整理部分本号发过的程序员成长方面的文章,供读者查阅。由于之前发布的内容多达数百篇,本次选择几十篇以做代表梳理。效率、如何提问、程序员的品格程序员当属工程师类别,而工程师的核心能力,在我看...

u013527895的博客 978

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

CTO更迭下的技术战略传导与工程师应对指南

在软件工程领域,技术战略的制定与传导是组织效能提升的核心环节。其原理在于通过清晰的决策链路,将顶层技术愿景转化为可落地的工程实践。这一过程的技术价值在于确保技术投资与业务目标对齐,提升系统的可维护性、扩展性与团队交付效率。典型的应用场景包括技术栈选型、架构治理模式升级、研发流程优化以及团队能力模型重塑。当组织发生技术领导层变动时,这一传导过程会加速并带来显著变化,例如可能推动云原生和微服务架构的普及,这要求一线从业者主动解读信号、评估新技术成本收益,并快速构建如Kubernetes与Go等新技能栈,从而在技

weixin_33946605的博客 411

从写代码到解问题:工程师的四层能力跃迁模型

在AI与产业深度融合的今天,单纯掌握编程语法已远不足以应对真实业务挑战。技术价值的本质在于将模糊需求转化为可计算、可验证、可闭环的问题定义——这要求工程师超越‘工程实现’,深入理解领域语义、构建严谨的问题建模、坚守约束驱动的开发范式,并建立以业务指标为锚点的价值反馈机制。本文基于37个跨行业落地项目经验,系统拆解‘编码仅占能力链10%’背后的冰山结构,聚焦领域知识沉淀、约束画布设计、DDD实践与价值熔断机制等关键方法论,帮助开发者从功能交付者升级为问题终结者。

weixin_30631587的博客 382

AtomCode与开发者成长:从代码搬运工到架构设计师的进阶之路

AtomCode 等 AI 编程工具的出现,不是开发者的"终结者",而是"进化加速器"。它们接管了低价值的重复劳动,让开发者有更多时间投入到高价值的创造性工作中。从代码搬运工到架构设计师的转变,不是一蹴而就的,而是一个持续学习、持续实践、持续反思的过程。AtomCode 可以加速这个过程,但无法替代这个过程——因为成长的核心,不是掌握更多工具,而是提升思维层次。“AI 不会取代开发者,但会用 AI 的开发者会取代不会用 AI 的开发者。

从事移动开发八年,csdn博客专家,阿里云特邀专家,华为云云享专家,高级网络信息安全工程师,大数据工程师(高级),python技术开发(高级),HarmonyOS 应用开发者高级认证,现在某学校任教。 5921

CnOpenData A股上市公司招聘数据

就业是经济的“晴雨表”,更是社会的“稳定器”。稳定和扩大就业一直是国家宏观调控的重要目标,2021年中央经济工作会议八次提到“就业”这一关键词。在新冠肺炎疫情蔓延、世界经济下行及人口老龄化加快等多重因素的叠加之下,稳就业保民生成为我国当前及今后一段时间内的工作重点。招聘最直接的目的就是弥补企业人力资源的不足,这是招聘工作的前提。

CnOpenData_wj的博客 368

《领域驱动设计之php实现》- 聚合【转载】

聚合可能是领域驱动设计中最难的构建块了。它们难以理解,并且难以正确设计。但不用担心,我们会帮助你。不过,在进入聚合之前,我们首先需要深入了解一些概念:事务和并发策略。 介绍 如果你使用过电子商务应用,则可能已经遇到过与数据库中数据不一致有关的错误。 例如,考虑一个总额为 99.99 美元的购物订单,该订单与订单中每行总金额的总和 89.99 美元不匹配。那这笔额外的 10 美元来自哪里? 或者,考虑一个为影院售卖电影票的网站。有一个剧院有 100 个可用座位,并且在电影成功上映之后,每个人都在网站上等待购票

tiway的博客 941

构建高可用、可扩展的PHP企业级应用架构实战教程-2

本文系统介绍了企业级PHP应用架构从传统分层模式向领域驱动设计(DDD)的演进过程。重点阐述了DDD的四大核心构建块:实体(具有唯一标识)、值对象(描述属性)、聚合根(维护业务一致性)和仓储(持久化管理),并通过PHP代码示例展示了它们的实现方式与协作关系。文章强调这一转变不仅是技术层面的更新,更是设计思维的升级,帮助开发者将业务逻辑内聚于领域模型中,而非分散在服务层,从而更好地应对复杂业务场景的需求。

zwh821的博客 947
上一篇: SpringBoot 加载外部 Jar,实现功能按需扩展!
下一篇: 领导要求下班前画一张图把分布式事务问题说清楚
程序员职业指南
博客等级 码龄4年 2136粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值