Java设计模式之依赖倒置原则使用举例说明

示例1:司机驾驶汽车

问题场景:司机类直接依赖奔驰车类,新增宝马车需修改司机类代码。

java 复制代码
// 未遵循DIP
class Benz { public void run() { /*...*/ } }
class Driver { 
    public void drive(Benz benz) { benz.run(); } 
}
// 遵循DIP:引入接口ICar
interface ICar { void run(); }
class Benz implements ICar { /*...*/ }
class BMW implements ICar { /*...*/ }
class Driver { 
    public void drive(ICar car) { car.run(); } 
}

效果:新增汽车类型(如BMW)无需修改Driver类,仅需实现ICar接口。


示例2:用户接收消息

问题场景:用户类直接依赖邮件类,新增微信或短信需修改用户类。

java 复制代码
// 未遵循DIP
class Email { public String getInfo() { /*...*/ } }
class Person { 
    public void receive(Email email) { /*...*/ } 
}
// 遵循DIP:引入接口IReceiver
interface IReceiver { String getInfo(); }
class Email implements IReceiver { /*...*/ }
class WeChat implements IReceiver { /*...*/ }
class Person { 
    public void receive(IReceiver receiver) { /*...*/ } 
}

效果:新增消息类型(如WeChat)无需修改Person类,仅需实现IReceiver接口。


示例3:购物场景

问题场景:顾客类直接依赖具体商品类(如汉堡、薯条),新增商品需修改顾客类。

java 复制代码
// 未遵循DIP
class Hamburger { public void eat() { /*...*/ } }
class Person { 
    public void buy(Hamburger hamburger) { hamburger.eat(); } 
}
// 遵循DIP:引入接口IDishes
interface IDishes { void eat(); }
class Hamburger implements IDishes { /*...*/ }
class Chips implements IDishes { /*...*/ }
class Person { 
    public void buy(IDishes dishes) { dishes.eat(); } 
}

效果:新增商品类型(如Chips)无需修改Person类,仅需实现IDishes接口。


示例4:通知服务

问题场景:通知服务直接依赖邮件发送类,更换短信服务需修改通知逻辑。

java 复制代码
// 未遵循DIP
class EmailService { public void sendEmail(String msg) { /*...*/ } }
class NotificationService { 
    public void send(String msg) { new EmailService().sendEmail(msg); } 
}
// 遵循DIP:引入接口MessageSender
interface MessageSender { void sendMessage(String msg); }
class EmailService implements MessageSender { /*...*/ }
class SMSService implements MessageSender { /*...*/ }
class NotificationService { 
    private MessageSender sender; 
    public NotificationService(MessageSender sender) { 
        this.sender = sender; 
    } 
    public void send(String msg) { sender.sendMessage(msg); } 
}

效果:通过构造器注入依赖,更换消息服务(如SMSService)仅需修改调用层。


依赖传递的三种方式

  1. 接口传递:通过方法参数传递抽象(如Driver.drive(ICar car))。
  2. 构造器注入:通过构造函数依赖注入(如NotificationService依赖MessageSender)。
  3. Setter注入:通过Setter方法动态注入依赖(如public void setSender(MessageSender sender))。

DIP的核心优势

  1. 降低耦合性:模块间通过抽象交互,减少直接依赖。
  2. 提高扩展性:新增功能只需添加实现类,无需修改高层逻辑(符合开闭原则)。
  3. 支持并行开发:接口定义后,高低层模块可独立开发与测试(如TDD模式)。
  4. 增强可维护性:变更影响范围受限于低层模块,减少风险。

总结

依赖倒置原则通过抽象(接口/抽象类)实现模块解耦,核心实践包括:

  • 定义清晰的接口或抽象类作为模块间的契约。
  • 使用依赖注入(构造器、Setter等)传递具体实现。
  • 高层模块仅依赖抽象,低层模块实现抽象。
    结合Spring框架的DI容器,可进一步自动化依赖管理,提升代码复用性和灵活性。