shangxijie

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

Dependence Inversion Principle”依赖倒置原则

说明:要依赖于抽象,不要依赖于具体。客户端依赖于抽象耦合。

抽象不应当依赖于细节;细节应当依赖于抽象;

要针对接口编程,不针对实现编程。

优点:使用传统过程化程序设计所创建的依赖关系,策略依赖于细节,这是糟糕的,因为策略受到细节改变的影响。依赖倒置原则使细节和策略都依赖于抽象,抽象的稳定性决定了系统的稳定性。

怎样做到依赖倒置?

以抽象方式耦合是依赖倒转原则的关键。抽象耦合关系总要涉及具体类从抽象类继承,并且需要保证在任何引用到基类的地方都可以改换成其子类,因此,里氏代换原则是依赖倒转原则的基础。

在抽象层次上的耦合虽然有灵活性,但也带来了额外的复杂性,如果一个具体类发生变化的可能性非常小,那么抽象耦合能发挥的好处便十分有限,这时可以用具体耦合反而会更好。

层次化:所有结构良好的面向对象构架都具有清晰的层次定义,每个层次通过一个定义良好的、受控的接口向外提供一组内聚的服务。

依赖于抽象:建议不依赖于具体类,即程序中所有的依赖关系都应该终止于抽象类或者接口。尽量做到:

1、任何变量都不应该持有一个指向具体类的指针或者引用。

2、任何类都不应该从具体类派生。

3、任何方法都不应该覆写它的任何基类中的已经实现的方法。

上面所叙述的只是一些理论性的东西,下面举个例子或许能更好地说明问题,

首先假设有一个需求,类Business需要调用类Dependency的方法f(),按照日常的做法,得到下面的代码:

//**类Dependency**
public class Dependency {
    public void f() {};
}
//**类Business**
public  class Business {
    Dependency d;
    public Business() {
    d = new Dependency();
    }
    public void doSth() {
        d.f();
    }
}

对上述实现做出如下修改:
    首先,将Business里的Dependency实例的获得该为setter方式,其次,将Dependency类改为某个接口的实现。故可以得到下面新的代码:
//**接口IDependency**
public interface IDependency {
    void f();
}
//**类Dependency**
public class Dependency {
    public void f() {};
}
//**类Business**
public  class Business {
    IDependency d;            //如果在构造函数里new一个具体的类的话,那么这段代码还是不能复用,一些书上在这个类中的某个函数中new一个具体的类,当然
    public Business() {}      //在具体类发生变化的时候,这段代码还得改,还是不能复用,高层还是依赖于具体,所以对读者是一种误解。所以应该采取依赖注
    public void doSth() {     //的方法,让外界来决定什么时候来传入一个具体的类,这就是好莱芜原则,只要具体类实现了某个稳定的接口,那么这个类
     d.f();                   //Business就能在以后的开发中得到复用,所以不只是继承才能复用,继承只是比较狭隘的复用,面向对象的复用强调的是逻辑的
    }                         //复用,只有这样才能在开发中节省大量的人力。所以依赖倒置应该于依赖注入联系起来,不能分离使用(个人看法)。
    public void setDependency(IDependency d) {
        this.d = d;
    }
}

在新的代码中,首先Business的变量d可以接收任何IDependency的实例,另外,Dependency的实例不是通过Business来获得,而是通过setter(也可以用构造器)来由外部传给它。这似乎跟我们往常的代码没什么不同,但这已经是一个良好的设计。

 

posted on 2009-03-06 22:48  尚希杰  阅读(370)  评论(0编辑  收藏  举报