2.3.4、依赖倒置原则

依赖倒置原则 Dependence Inversion Principle

定义

高层模块不应该依赖低层模块,两者都应该依赖其抽象 , High level modules should not depend upon low level modules. Both should depend upon abstractions.

抽象不应该依赖细节,Abstractions should not depend upon details.

细节应该依赖抽象,Details should depend upon abstractions.

传统的过程性系统的设计方法倾向于使抽象层次依赖于具体层次。倒置原则就是要把这个错误的依赖关系倒转过来。

通俗来讲就是:

1、每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备 

2、变量的显示类型尽量是接口或者是抽象类 

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

4、尽量不要覆写基类的方法 

5、结合里氏替换原则使用 

举一个例子。

假设我们开发一个登录系统。需要完成界面+业务逻辑代码+数据存储。我们先只说业务逻辑代码里面的注册用户和密码功能,他目前有两种方式,一、是网页注册的,二是手机注册,如下

传统的写法是创建注册类,然后创建数据保存类。如下

1、不符合DIP写法:

//数据库操作代码
public class DBSave {
    //这里有人可能会说不符合单一职责,但是对于数据库来说,保存插入一条新数据,
    // 里面包含多个字段其实是可以用一句jobc解决的,视为一个单一功能
    public void saveMsgFromWeb(String Name, String Pwd)
    {
        Log.e("ldy","用户名:"+Name+";密码"+Pwd+";注册类型:网页,"+"保存成功,不符合DIP");
    }

    public void saveMsgFromPhone(String name, String pwd) {
        Log.e("ldy","用户名:"+name+";密码"+pwd+";注册类型:手机,"+"保存成功,不符合DIP");
    }
}
//注册
public class Register {
    public void registerFromWeb(DBSave dbSave,String Name,String Pwd) {
        dbSave.saveMsgFromWeb(Name,Pwd);
    }
    public void registerFromPhone(DBSave dbSave,String Name,String Pwd) {
        dbSave.saveMsgFromPhone(Name,Pwd);
    }
}
//测试代码
  Register register=new Register();
  DBSave dbSave=new DBSave();
  register.registerFromWeb(dbSave,"张三","123456");
  register.registerFromPhone(dbSave,"李四","654321");

2、如果要符合依赖倒置,首先要创建接口。然后创建抽象类,然后继承抽象类继承不同的功能。如下:

/**
 *  抽象层
 **/
//先创建接口
public interface IDb {
     void saveMsg(String Name, String Pwd);
}
public interface IRegister {
     void register(DbSave dbSave, String Name, String Pwd) ;
}
//在创建抽象类,这里的抽象类可有可无,为了演示,我还是把他写出来了。
public abstract class DbSave implements IDb{
}
public abstract class RegisterAbstract implements IRegister {
}

/**
 *  底层模块
 **/
public class DbSaveFromPhone extends DbSave{

    @Override
    public void saveMsg(String Name, String Pwd)
    {
        Log.e("ldy","用户名:"+Name+";密码"+Pwd+";注册类型:手机"+"保存成功,符合DIP");
    }

}
public class DbSaveFromWeb extends DbSave{

    @Override
    public void saveMsg(String Name, String Pwd)
    {
        Log.e("ldy","用户名:"+Name+";密码"+Pwd+";注册类型:网页"+"保存成功,符合DIP");
    }

}
public class RegisterUser extends RegisterAbstract {
    @Override
    public void register(DbSave dbSave, String Name, String Pwd) {
        dbSave.saveMsg(Name,Pwd);
    }
}

 上面例子展示了细节应该依赖于抽象。

另外如果还有高层模块,也不应该依赖底层模块而应该依赖抽象层,

还有任何类都不应该从具体类派生 ,如果手机注册还要细分成苹果和安卓,要不就新增两个实现类苹果和安卓去依赖注册抽象类,要不就是把手机注册实现类改成抽象类,给苹果和安卓实现类去依赖。不建议苹果实现类去依赖手机注册实现类。

简单代码结果如下

依赖的三种写法

构造函数传递依赖对象

Setter方法传递依赖对象



接口声明依赖对象

接口的方法中声明依赖对象


发布了39 篇原创文章 · 获赞 2 · 访问量 5005

猜你喜欢

转载自blog.csdn.net/u013636987/article/details/104160980
今日推荐