惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
G
Google Developers Blog
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
云风的 BLOG
云风的 BLOG
小众软件
小众软件
月光博客
月光博客
Recent Announcements
Recent Announcements
人人都是产品经理
人人都是产品经理
P
Proofpoint News Feed
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
雷峰网
雷峰网
The Cloudflare Blog
博客园_首页
美团技术团队
大猫的无限游戏
大猫的无限游戏
B
Blog
IT之家
IT之家
Jina AI
Jina AI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
C
Check Point Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

博客园 - jadesun

【转载】Zachman框架 参加了IBM的架构师培训,总结了一些内容 数据仓库 - 事实表和维度表建立的方法论 Hadoop的学习历程 Hadoop手册_v0.3 MySQL_Cluster 的尝试及各种测试 Hadoop的学习历程 Hadoop手册_v0.2 尝试数据分片处理 和同事扯了一个理论模型出来,后面再验证是否合理。 迪米特法则 中国航油项目的一次数据库优化,关于Audit Logout的问题。 公文流转SQL优化日志七 公文流转SQL优化日志六 和同事们终于将Entity FrameWork整合进新的框架中了,发布第一个版本。 继续上篇实现的架构,有了新的进展。介绍一下格瑞趋势的产品 公文流转SQL优化日志五 工作日志,正在实现中的架构,针对SQL SERVER。参考了DZ的设计 公文流转SQL优化日志四 公文流转SQL优化日志三 公文流转SQL优化日志二
依赖倒置原则
jadesun · 2012-03-20 · via 博客园 - jadesun

依赖倒置原则(Dependence Inversion Principle, DIP),有三层含义:

1,高层模块不应该依赖低层模块,两者都应该依赖期抽象。

2,抽象不应该依赖细节。

3,细节应该依赖抽象。

高层模块:每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是低层模块。

低层模块:原子逻辑的再组装就是高层模块。

抽象:抽象是指接口或者抽象类,两者都是不能直接被实例化的。

细节:实现接口或继承抽象类面产生的类就是细节,其特点就是可以直接被实例化,也就是可以加一个关键字new产生一个对象。

上面三层含义的具体表现就是:

1,模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。

2,接口或抽象类不依赖于实现类。

3,实现类依赖接口或抽象类。

更加精简的定义就是  面向接口编程

示例一份没有使用依赖倒置原则的代码:

//司机源代码
public class Driver{
    public void drive(Benz benz){
        benz.run();
    }
}

//奔驰车源代码
public class Benz{
    public void run(){
        System.out.println("奔驰汽车开始运行....");
    }
}

//场景类源代码
public class Client{
    public static void main(String[] args){
        Driver siji = new Driver(); //实例一个司机对象。
        Benz benz = new Benz(); //实例一个奔驰车对象。
        sji.drive(benz); //司机开着奔驰车跑了起来。
    }
}

通过以上的代码,完成了司机开动奔驰车的场景。达到了基本需求,但是发生项目变更时,就会有问题。现在加入宝马车,那司机就开不动了。因为在Driver这个类中我们将依赖了Benz这个类的实例,导致了类之间的紧耦合

依照依赖倒置原则,将示例代码改成如下的方式:

//定义司机接口,可能会有张三司机、李四司机
public interface IDriver{
    //是司机就应该会驾驶汽车
    public void drive(ICar car);
}

//定义汽车接口,可能有宝马、奔驰
public interface ICar{
    //是汽车都应该能跑
    public void run();
}

//司机的实现类
public class Driver implements IDriver{
    public void drive(ICar car){
        car.run();
    }
}

//奔驰汽车的实现类
public class Benz implements ICar{
    public void run(){
        System.out.println("奔驰汽车....");
    }
}

//宝马汽车的实现类
public class BMW implements ICar{
    public void run(){
        System.out.println("宝马汽车....");
    }
}

//场景类
public class Client{
    public static void main (String[] args){
        IDriver zhangshan = new Driver();
        ICar benz = new Benz();
        ICar bmw = new BMW();
        //张三开奔驰
        zhangshan.drive(benz);
        //张三开宝马
        zhangshan.drive(bmw);
    }
}

 摘录一篇关于IOC实现依赖倒置的实现理论的文章。

---- 概念 ----

◆1.依赖倒置原则(DIP,Dependency Inverse Principle)
    强调系统的高层组件不应当依赖于底层组件;并且不论是高层组件还是底层组件都应当依赖于抽象。

◆2.依赖(Dependency)
    组件A如果:①.持有B的引用,②调用B的方法,③创建(new)B,则A对B产生依赖

◆3.控制(Control)
    A依赖B,则B拥有“控制权”,因为B的某种变化可能会引起A的变化

◆4.控制反转(IoC,Inverse of Control)
    就是将控制方“往高处/上层”转移
    控制反转是实现依赖倒置的一种方法

◆5.依赖注入(DI,Dependency Injection)
    组件通过构造函数或者setter方法,将其依赖暴露给上层;上层要设法取得组件的依赖,并将其传递给组件。
    依赖注入是实现控制反转的一种手段

---- DIP,DI与IoC 不得不说的故事 ----

“高层组件不应当依赖于低层组件;并且不论是高层组件还是低层组件都应当依赖于抽象!”
                              —— DIP

于是,按照DIP说的,我们把底层组件抽象为接口与实现类,高层组件依赖此接口。看起来,大家都是依赖抽象了,不过,我们应该在何处、如何取得具体的底层组件实例??

1.通过底层组件工厂(纯虚构),将"new"操作"集中起来管理"。于是高层组件对底层组件的依赖转变为了对"纯虚构"出来的工厂的依赖(这就是IoC的一种实现手段)。新的问题来了,其实工厂也是不小的麻烦。
(地点:高层组件内部;方式:通过底层组件工厂)

2.高层组件咆哮到:“底层组件和工厂都TM伤不起!动不动就变!!有木有!!我不管了啊!要调用我的组件们,我给你们开放注入具体实现的接口(构造函数注入,setter/getter注入),你们自己看着办啊 !!!”——于是,依赖注入(DI)的基础建立了起来,同时,对依赖关系的管理任务也交给了上层(这就是IoC的一种实现手段)。
(地点:高层组件的使用者内部;方式:设法取得具体实现,并传递给高层组件)

2.5 高层组件的高层组件无语了,但是它很淡定地如法炮制,将这个“麻烦”交给了它的高层组件,and so on...最终,最高处的那个组件(一般它叫“应用”),表示鸭梨非常大:“你们把所有的依赖都转给我了?!?!这不是坑爹吗?”

3.此时,"工厂"的角色和范畴扩大,它接纳了“管理整个应用的所有实现类对象”的任务。它通过某种方式(比如Spring的XML配置方式、注解方式;Guice的编程方式)向应用提供了管理组件之间依赖关系的接口,于是,应用所要考虑的所有依赖关系都可以委托给这样的"工厂"了,"工厂"成为了应用唯一依赖 —— 整个应用的“控制权”全都由具体实现(包括底层组件具体实现、甚至底层组件工厂等)反转至了"工厂"的依赖接口中,“IoC容器”是它响亮的新名字!
(地点:IoC容器;方式:通过IoC容器的API)

4.IoC容器的引入,让整个应用变得十分灵活,组件之间可以“热插拔”。这也正是DIP的初衷。

 * 通过IoC容器,我们在使用一个组件时,需要指定它的依赖,以及它的依赖的依赖...and so on,这形成了一个“对象图”的概念

 关于IOC解耦合的实例及好处,可以看以下的文章。