迪米特法则(Law of Demeter, LoD)是一种软件设计原则,它要求一个对象应该对其他对象有最少的了解,只与直接的朋友(即直接的依赖关系)交互。
肖哥弹架构 跟大家“弹弹” 代码设计技巧,需要代码关注
欢迎 点赞,点赞,点赞。
关注公号Solomon肖哥弹架构获取更多精彩内容
历史热点文章
- 数据访问对象模式(Data Access Object Pattern):电商平台商品管理实战案例分析
- Holder模式(Holder Pattern):公司员工权限管理系统实战案例分析
- 一个项目代码讲清楚DO/PO/BO/AO/E/DTO/DAO/ POJO/VO
2. 迪米特法则设计图:
电子商务中库存服务如何遵守迪米特法则:
3. 迪米特法则解决什么:
迪米特法则解决了在复杂系统中对象之间不必要交互的问题,减少了系统的耦合度。
4.迪米特法则特点:
- 最小化交互:类只与直接相关对象交互。
- 提高模块化:降低了类之间的依赖,提高了系统的模块化。
5. 迪米特法则缺点:
- 可能增加间接层:为了遵守迪米特法则,可能需要增加额外的间接层或中间类。
- 过度封装:在一些情况下,可能会导致过度封装,影响代码的直观性。
6. 迪米特法则使用场景:
当系统中的对象之间存在复杂的交互关系,或者一个对象需要了解太多其他对象的内部细节时。
7. 迪米特法则案例
7.1 库存和订单处理案例
重构前:
// OrderService 直接与 Product 交互,违反了迪米特法则
public class OrderService {
public void placeOrder(Product product, int quantity) {
if (product.getStock() >= quantity) {
product.reduceStock(quantity);
product.getSupplier().notifyStockLevel(); // 间接交互
// 发送订单确认逻辑
} else {
// 发送缺货通知逻辑
}
}
}
public class Product {
private int stock;
private Supplier supplier;
public int getStock() {
return stock;
}
public void reduceStock(int quantity) {
stock -= quantity;
}
public Supplier getSupplier() {
return supplier;
}
}
public class Supplier {
public void notifyStockLevel() {
// 库存水平通知逻辑
}
}
问题分析:
- 高耦合度:
OrderService
直接与Product
类的多个方法交互,包括获取库存和减少库存,这增加了类之间的依赖。 - 低内聚性:
Product
类不仅管理自己的状态,还负责与Supplier
交互,这违反了单一职责原则。 - 扩展性差:当需要添加新的库存检查逻辑或供应商通知逻辑时,可能需要修改
OrderService
的代码,这限制了系统的扩展性。 - 代码重复:如果系统中的其他部分需要进行库存检查或减少库存,可能会复制
OrderService
中的代码,导致代码重复。 - 测试困难:直接依赖具体实现使得对
OrderService
进行单元测试变得复杂,因为它依赖于多个外部实体。
重构后:
// 库存服务接口,定义库存相关操作的契约
public interface IInventoryService {
boolean isStockSufficient(Product product, int quantity);
void reduceStock(Product product, int quantity);
}
// 实现库存服务接口的具体类
public class InventoryService implements IInventoryService {
@Override
public boolean isStockSufficient(Product product, int quantity) {
// 检查库存是否充足
return product.getStock() >= quantity;
}
@Override
public void reduceStock(Product product, int quantity) {
// 减少产品库存
product.reduceStock(quantity);
}
}
// 订单服务类,负责处理订单逻辑
public class OrderService {
private IInventoryService inventoryService;
// 依赖注入库存服务
public OrderService(IInventoryService inventoryService) {
this.inventoryService = inventoryService;
}
// 下订单的方法
public void placeOrder(Product product, int quantity) {
if (inventoryService.isStockSufficient(product, quantity)) {
inventoryService.reduceStock(product, quantity);
sendOrderConfirmationEmail(product, quantity);
} else {
sendOutOfStockNotificationEmail(product);
}
}
private void sendOrderConfirmationEmail(Product product, int quantity) {
// 发送订单确认邮件逻辑
// 这里用注释代替真实的邮件发送逻辑
// EmailService.send("Order confirmed for " + product.getName());
}
private void sendOutOfStockNotificationEmail(Product product) {
// 发送缺货通知邮件逻辑
// 这里用注释代替真实的邮件发送逻辑
// EmailService.send("Out of stock notification for " + product.getName());
}
}
// 产品类,包含库存和供应商信息
public class Product {
private int stock;
private String name;
private Supplier supplier;
public Product(String name, int stock, Supplier supplier) {
this.name = name;
this.stock = stock;
this.supplier = supplier;
}
public int getStock() {
return stock;
}
public void setStock(int stock) {
this.stock = stock;
}
public void reduceStock(int quantity) {
stock -= quantity;
if (stock <= 10) {
supplier.notifyLowStock(this);
}
}
public String getName() {
return name;
}
}
// 供应商类,负责接收库存水平通知
public class Supplier {
public void notifyLowStock(Product product) {
// 库存水平通知逻辑,可能涉及外部系统或服务 ,篇幅问题省略
}
}
// 客户端代码,使用OrderService和InventoryService
public class ECommerceClient {
public static void main(String[] args) {
Product product = new Product("Laptop", 5, new Supplier());
IInventoryService inventoryService = new InventoryService();
OrderService orderService = new OrderService(inventoryService);
// 尝试下订单
orderService.placeOrder(product, 3);
// 尝试下超过库存的订单
orderService.placeOrder(product, 10);
}
}
解决的问题:
- 解耦合:通过引入
IInventoryService
接口,OrderService
现在只依赖于库存服务的抽象,而不是具体的Product
类。 - 高内聚性:
Product
类现在只负责管理自己的状态,而库存检查和减少库存的逻辑由InventoryService
处理,符合单一职责原则。 - 扩展性增强:新增或修改库存逻辑时,只需实现或修改
IInventoryService
的具体实现类,无需更改OrderService
。 - 减少代码重复:库存检查和减少库存的逻辑现在集中在
InventoryService
中,可以在多个地方重用,减少了代码重复。 - 易于测试:
OrderService
和InventoryService
可以独立测试,因为它们之间的依赖是通过接口定义的,可以轻松地使用模拟对象进行测试。 - 清晰的职责划分:每个类和接口都有明确的职责,
OrderService
处理订单逻辑,InventoryService
处理库存逻辑,Product
管理产品状态。 - 更好的维护性:由于系统更加模块化,维护和更新特定部分的代码变得更加容易,因为对系统的其他部分的影响最小。
7.2 课程管理系统
重构前:
public class Professor {
private String name;
public Professor(String name) {
this.name = name;
}
public void submitGrades(Student student, Course course, double grade) {
course.getEnrolledStudents().add(student);
student.addGrade(course, grade);
System.out.println("Grade submitted by " + name);
}
}
public class Course {
private List<Student> enrolledStudents;
public void addStudent(Student student) {
enrolledStudents.add(student);
}
public List<Student> getEnrolledStudents() {
return enrolledStudents;
}
}
public class Student {
private List<Grade> grades;
public void addGrade(Course course, double grade) {
grades.add(new Grade(course, grade));
}
}
public class Grade {
private Course course;
private double grade;
public Grade(Course course, double grade) {
this.course = course;
this.grade = grade;
}
}
分析问题:
- 违反迪米特法则:
Professor
类直接与Student
和Course
的具体实现交互。 - 高耦合度:
Professor
类与Course
和Student
类的内部状态紧密耦合。 - 低内聚性:
Course
类不仅管理课程信息,还管理学生注册和成绩记录。
重构后:
// 教授类,只负责教授相关逻辑
public class Professor {
private String name;
public Professor(String name) {
this.name = name;
}
public void submitGrade(CourseGradeService courseGradeService, Course course, double grade) {
courseGradeService.recordGrade(course, grade);
System.out.println("Grade submitted by " + name);
}
}
// 课程成绩服务,负责处理成绩记录逻辑
public class CourseGradeService {
public void recordGrade(Course course, double grade) {
course.addGrade(grade);
}
}
// 课程类,只负责课程相关逻辑
public class Course {
private List<Double> grades;
public void addGrade(double grade) {
grades.add(grade);
}
}
// 学生类保持不变,只关注学生自己的成绩
public class Student {
private List<Grade> grades;
public void addGrade(Course course, double grade) {
grades.add(new Grade(course, grade));
}
}
// 成绩类保持不变
public class Grade {
private Course course;
private double grade;
public Grade(Course course, double grade) {
this.course = course;
this.grade = grade;
}
}
// 客户端代码
public class UniversityClient {
public static void main(String[] args) {
Professor professor = new Professor("Dr. Smith");
Course course = new Course();
CourseGradeService courseGradeService = new CourseGradeService();
professor.submitGrade(courseGradeService, course, 92.5);
}
}
解决的问题:
- 遵守迪米特法则:
Professor
类现在只与CourseGradeService
交互,而不是直接与Course
或Student
交互。 - 降低耦合度:通过引入
CourseGradeService
,Professor
类不再依赖于Course
类的内部实现。 - 提高内聚性:
Course
类现在只关注课程和成绩管理,而Professor
类只关注教授的行为。 - 增强扩展性:新增或修改成绩记录逻辑时,只需在
CourseGradeService
中进行,不影响其他类。 - 简化测试:可以独立测试
CourseGradeService
的行为,而不需要依赖Professor
或Course
类。
8. 参考开源框架:
在现代的电子商务平台中,如Magento或Shopify,通常会遵循迪米特法则来设计库存和订单服务。
9. 总结:
通过应用迪米特法则,电子商务平台的库存管理和订单服务变得更加清晰和解耦。这不仅提高了代码的可维护性,也使得新增功能或修改现有逻辑变得更加容易。迪米特法则是构建低耦合、高内聚系统的有效工具之一。
历史热点文章
- 享元模式(Flyweight Pattern):网页游戏中的角色对象管理实战案例分析
- 观察者模式(Observer Pattern):股票交易系统实战案例分析
- 策略模式(Strategy Pattern):电商平台的优惠券系统实战案例分析
- 模板方法模式(Template Method Pattern):视频播放应用实战案例分析
- 命令模式(Command Pattern):网络爬虫任务队列实战案例分析
- 迭代器模式(Iterator Pattern):电商平台商品分类浏览实战案例分析
- 中介者模式(Mediator Pattern):即时通讯软件实战案例分析
- 备忘录模式(Memento Pattern):游戏存档系统实战案例分析
- 状态模式(State Pattern):电商平台订单状态管理实战案例分析
- 责任链模式(Chain of Responsibility Pattern):电商平台的订单审批流程实战案例分析
- 访问者模式(Visitor Pattern):电商平台商品访问统计实战案例分析
- 工厂方法模式(Factory Method Pattern): 电商多种支付实战案例分析
- 抽象工厂模式(Abstract Factory Pattern):多风格桌面应用实战案例分析
- 建造者模式(Builder Pattern): 在线订单系统实战案例分析
- 原型模式(Prototype Pattern): 云服务环境配置实战案例分析
- 适配器模式(Adapter Pattern):第三方支付集成实战案例分析
- 装饰器模式(Decorator Pattern):电商平台商品价格策略实战案例分析
- 单例模式(Singleton Pattern):购物车实战案例分析