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

推荐订阅源

Google DeepMind News
Google DeepMind News
Stack Overflow Blog
Stack Overflow Blog
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
T
The Blog of Author Tim Ferriss
博客园 - 叶小钗
N
Netflix TechBlog - Medium
腾讯CDC
C
Check Point Blog
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
S
SegmentFault 最新的问题
F
Fortinet All Blogs
美团技术团队
U
Unit 42
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 司徒正美
F
Full Disclosure
Recorded Future
Recorded Future
D
DataBreaches.Net
博客园 - 【当耐特】
Martin Fowler
Martin Fowler
J
Java Code Geeks
I
InfoQ
Y
Y Combinator Blog
A
About on SuperTechFans
AI
AI
爱范儿
爱范儿
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Forbes - Security
Forbes - Security
W
WeLiveSecurity
M
MIT News - Artificial intelligence
雷峰网
雷峰网
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
Schneier on Security
Schneier on Security
The GitHub Blog
The GitHub Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
aimingoo的专栏
aimingoo的专栏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
GRAHAM CLULEY
Know Your Adversary
Know Your Adversary
Latest news
Latest news
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Docker
Recent Commits to openclaw:main
Recent Commits to openclaw:main
量子位
V2EX - 技术
V2EX - 技术
Project Zero
Project Zero

博客园 - 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解耦合的实例及好处,可以看以下的文章。