| public class Person { |
| |
| |
| private String id; |
| |
| |
| private String name; |
| |
| |
| private Address address; |
| } |
| |
| public class Address { |
| |
| |
| private String province; |
| |
| private String city; |
| |
| private String street; |
| } |
| |
| # 值对象创建后不允许修改,只能用另外一个值对象来整体替换 |
| # 值对象没有id,会被实体整体引用 |
- 案例一:值对象中只有一个属性
- 案例二:值对象中有多个属性,但只有一条记录的多属性值对象的实体
| # 以上2种情况,将值对象的属性直接嵌入实体类 |
| public class Person { |
| |
| private String id; |
| |
| private String name; |
| |
| private String province; |
| |
| private String city; |
| |
| private String street; |
| } |
- 当值对象中包含多个属性时,且会引用多条记录的多属性值对象的实体
| # 以序列化大对象方式形成的实体对象,值对象则设计为Class类,值对象被序列化成大对象JSON串后,嵌入实体类中 |
| public class Person { |
| |
| private String id; |
| |
| private String name; |
| |
| private Address address; |
| } |
| |
| public class Address { |
| |
| private String province; |
| |
| private String city; |
| |
| private String street; |
| } |
| └── demo |
| ├── application |
| | ├── event |
| | | ├── publish # 发布接口 + 实现 |
| | | └── subscribe # 订阅接口 + 实现 |
| | | |
| | └── service # 应用接口 + 实现 |
| | |
| ├── domain |
| | ├── aggregate1 |
| | | ├── event # 存放事件实体,以及事件的具体业务逻辑实现 |
| | | | |
| | | ├── model |
| | | ├── repository |
| | | └── service # 领域服务接口 + 实现 |
| | | |
| | └── aggregate2 |
| | |
| ├── infrastructure |
| | |
| └── interfaces |
| |
| # 个人理解:领域事件主要是用于跟踪已经发生的事,传递需要通知的消息,记录会引起其他模型对象改变状态的事件 |
| # 例如使用rabbitmq进行发布和订阅消息 |
| # <应用层中的event + 领域层中的event>写法与<应用服务 + 领域服务>类似 |
| # 在两个微服务之间相互调用时,需要利用防腐层进行隔离 |
| # 上游微服务 -> 防腐层(接口 + 实现) -> 下游微服务 |
| # 这里的防腐层通常是我们使用的feign接口 + 实现 |
| # 在防腐层中将上游数据模型转换为下游微服务所需的数据模型;例如在feign实现类中进行转换,参考chnx/cloud/seata01 |
| # 防腐层往往属于下游限界上下文,用以隔绝上游限界上下文可能发生的变化 |
| |
| # 使用sentinel进行(异常、超时)降级 |
| # 数据校验:对上游数据模型进行校验 |
| # 接口防腐:将上游数据模型转为vo对象 |
| # 防腐层之间不能进行调用(必须) |
| # 防腐层不允许有大量的业务逻辑,业务逻辑部分上提到调用端(必须):职责单一清晰 |
| |
| 补充 |
| # 防腐层个人认为放在application中 |
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术