0106_依赖倒置原则

定义:高层模块不应该依赖低层模块,二者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象

场景

以人类和机器人对象为例,人类和机器人共同的动作有吃饭、行走。
Application

IHuman接口

  • 职责:人类行为接口,定义了人类的基本行为规范
public interface IHuman {
    /**
     * 吃饭行为
     */
    void eat();

    /**
     * 走路行为
     */
    void walk();
}

Human类

  • 职责:该类实现了IHuman接口定义的基础人类行为
public class Human implements IHuman {
    private int age;
    private String name;

    public Human(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public void eat() {
        System.out.println(this.name + "在吃饭");
    }

    public void walk() {
        System.out.println(this.name + "在走路");
    }

}

Robot类接口

  • 职责:该类实现了IHuman接口定义的机器人行为
public class Robot implements IHuman {
    private int age;
    private String name;

    public Robot(int age, String name) {
        this.age = age;
        this.name = name;
    }
    @Override
    public void eat() {
        System.out.println("机器人" + this.name + "正在充电");
    }
    
    @Override
    public void walk() {
        System.out.println("机器人" + this.name + "正在移动");
    }
}

反例

WrongHumanService类

  • 职责:违反依赖倒置原则,直接依赖具体实现类,而不是抽象接口
public class WrongHumanService {
    // 直接依赖具体实现类 Human,违反了依赖倒置原则
    private Human human;
    // 如果要支持机器人,就需要增加新的属性
    private Robot robot;
    
    // 直接依赖具体实现
    public WrongHumanService(Human human) {
        this.human = human;
    }
    public WrongHumanService(Robot robot) {
        this.robot = robot;
    }

    public void dailyRoutine() {
        human.eat();
        human.walk();
    }
    
    // 如果要支持机器人,需要添加新的方法
    public void robotRoutine() {
        robot.eat();
        robot.walk();
    }
}

在反例中,如果要支持多种实现,需要编写大量重复代码这种实现方式违背了依赖倒置原则,使得系统僵化、难以维护和扩展。。

正例

HumanService类

  • 职责:人类服务类,该类依赖于IHuman抽象接口,而不是具体的Human实现类
public class HumanService {
    // 声明对IHuman接口的依赖,不依赖具体实现类
    private IHuman human;
    
    // 通过构造函数注入依赖,确保对象创建时就具备完整功能
    public HumanService(IHuman human) {
        this.human = human;
    }
    
    // 通过setter方法注入依赖,提供运行时动态替换依赖的能力
    public void setHuman(IHuman human) {
        this.human = human;
    }
    
    // 执行日常行为,调用依赖接口的方法
    public void dailyRoutine() {
        human.eat();   // 调用吃饭行为
        human.walk();  // 调用走路行为
    }
}

Application类

  • 职责:应用程序入口,演示依赖倒置原则的使用
public class Application {
    public static void main(String[] args) {
        IHuman human = new Human(25, "张三");
        HumanService service = new HumanService(human);
        service.dailyRoutine();
        
        // 可以轻松替换为机器人
         IHuman robot = new Robot(1, "机器人");
         service.setHuman(robot);
         service.dailyRoutine();
    }
}
  • 解耦合:HumanService 不直接依赖 Human 类,而是依赖 IHuman 接口
  • 可扩展性:可以轻松添加新的 IHuman 实现(如 Robot)而不需要修改现有代码

总结

方面 反例(违反DIP) 正例(遵循DIP)
依赖关系 高层模块(Service)依赖低层模块(Human) 双方都依赖抽象(IHuman)
耦合度 紧耦合ServiceHuman强绑定 松耦合Service与具体实现无关
扩展性 ,增加新实现需修改Service内部 极佳,增加新实现只需实现接口,Service无需改动
维护性 ,一处改动可能引发多处连锁修改 ,代码稳定,修改的影响被隔离
可读性 较低,存在重复代码,逻辑分散 较高,代码简洁,意图清晰
可测试性 较差,难以隔离测试 极佳,易于注入Mock对象进行单元测试

核心要义:依赖倒置原则通过引入一个抽象接口层,将“策略”与“细节”分离,反转了传统的自上而下的依赖关系,使得软件架构能够更好地应对变化。针对接口编程,而不是针对实现编程,是实践这一原则的关键。

posted @ 2025-08-19 20:26  庞去广  阅读(7)  评论(0)    收藏  举报