设计模式原则之依赖倒转(倒置)原则

设计模式原则之依赖倒转(倒置)原则

原则概述

依赖倒转原则(Dependence Inversion Principle)是指: 高层模块不应该依赖底层模块,二者都应该依赖其(或接口)抽象(不要依赖具体子类) 。也就是说 抽象不应该依赖于细节,细节应当依赖于抽象;其核心思想是要面向接口编程,而不是面向实现编程。

实现方法

具体来说,当我们在代码中传递参数或搭建关联关系时,尽量引用层次高的抽象层类,也就是尽量使用接口和抽象类代替具体类来进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,尽量不要用具体类来做这些事情。

为了确保该原则的有效使用,就要遵守接口隔离原则,即一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法;否则将无法调用在子类中增加的新方法。

引入抽象层后,系统将具有很好的灵活性,在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样一来,如果系统行为发生变化,只需要对抽象层进行扩展,并修改配置文件,而无须修改原有系统的源代码,在不修改的情况下来扩展系统的功能,满足开闭原则的要求。

实现了依赖倒转原则,我们更多的时候是针对抽象层编程,而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其对应的抽象层中;
依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。
常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入。构造注入是指通过构造函数来传入具体类的对象,设值注入是指通过Setter方法来传入具体类的对象,而接口注入是指通过在接口中声明的业务方法来传入具体类的对象。这些方法在定义时使用的是抽象类型,在运行时再传入具体类型的对象,由子类对象来覆盖父类对象。

小结

依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性,所以我们在实际编程中只要遵循以下4点,就能在项目中满足这个规则:
1、每个类尽量提供接口或抽象类,或者两者都具备。
2、变量的声明类型尽量是接口或者是抽象类。
3、任何类都不应该从具体类派生。
4、使用继承时尽量遵循里氏替换原则

应用案例

比如有个Person类,可以接受Email、QQ和微信的消息。如果都为其提供一个专门的方法,就会让代码非常的冗余:
在这里插入图片描述
可以引入一个IReceiver接口,让Person类依赖该接口。这样QQ类、微信类和Email类各自实现IReceiver里面的方法即可:
在这里插入图片描述
对应的代码如下,

编程完成Person 接收消息 的功能。

public class DependecyInversion {

	public static void main(String[] args) {
		Person person = new Person();
		person.receive(new Email());
	}
}
class Email {
	public String getInfo() {
		return "电子邮件信息: hello,world";
	}
}
//完成Person接收消息的功能
//方式1分析
//1. 实现简单,比较容易想到
//2. Person类的receive方法直接接收了一个Email,问题是如果我们获取的对象是除了Email,
//还有从 微信,短信中获取信息 等等,则需要新增类,同时Perons也要增加相应的接收方法
//3. 解决思路:引入一个抽象的接口IReceiver, 表示接收者, 这样Person类与接口IReceiver发生依赖
//   因为Email, WeiXin 等等属于接收的范围,他们各自实现IReceiver 接口就ok, 这样我们就符号依赖倒转原则
class Person {
	public void receive(Email email ) {
		System.out.println(email.getInfo());
	}
}

​ Person类的receive方法直接接收了一个Email,问题是如果我们获取的对象是除了Email,还想要从 微信,短信等对象中获取信息 等等,这样我们就需要新增类,同时Perons也要增加相应的接收方法。

​ 解决方法:引入一个抽象的接口IReceiver, 表示接收者, 这样Person类与接口IReceiver发生依赖, 因为Email, WeiXin 等等属于接收的范围,他们各自实现IReceiver 接口就可以了, 这样我们就符合依赖倒转原则,而Person类不需要新增相应的接收方法,只需要将Person类的receive方法的参数变成IReceiver接口即可。

 

public class DependecyInversion {

	public static void main(String[] args) {
		//客户端无需改变
		Person person = new Person();
		person.receive(new Email());
		
		person.receive(new WeiXin());
	}
}
//定义接口
interface IReceiver {
	public String getInfo(); //做成抽象方法
}
class Email implements IReceiver {
	public String getInfo() {
		return "电子邮件信息: hello,world";
	}
}
//增加微信,实现IReceiver
class WeiXin implements IReceiver {
	public String getInfo() {
		return "微信信息: hello,ok";
	}
}
//方式2
class Person {
	//这里我们是对接口的依赖
	public void receive(IReceiver receiver ) {
		System.out.println(receiver.getInfo());
	}
}

在这里插入图片描述

依赖关系传递的三种方式和应用案例
  1. 接口传递
// 方式1: 通过接口传递实现依赖
// 开关的接口
interface IOpenAndClose {
	public void open(ITV tv); // 抽象方法,接收接口
}

interface ITV { // ITV接口
	public void play();
}

class ChangHong implements ITV {
	@Override
	public void play() {
		// TODO Auto-generated method stub
		System.out.println("长虹电视机,打开");
	} 
}
 实现接口
class OpenAndClose implements IOpenAndClose {
	public void open(ITV tv) {
		tv.play();
	}
}
  1. 构造方法传递
//方式2:通过构造方法依赖传递
interface IOpenAndClose {
	public void open(); // 抽象方法
}

interface ITV { // ITV接口
	public void play();
}

class OpenAndClose implements IOpenAndClose {
	public ITV tv; // 成员

	public OpenAndClose(ITV tv) { // 构造器
		this.tv = tv;
	}

	public void open() {
		this.tv.play();
	}
}

  1. setter方式传递
// 方式3 , 通过setter方法传递
interface IOpenAndClose {
	public void open(); // 抽象方法

	public void setTv(ITV tv);
}

interface ITV { // ITV接口
	public void play();
}

class OpenAndClose implements IOpenAndClose {
	private ITV tv;

	public void setTv(ITV tv) {
		this.tv = tv;
	}

	public void open() {
		this.tv.play();
	}
}

class ChangHong implements ITV {

	@Override
	public void play() {
		// TODO Auto-generated method stub
		System.out.println("长虹电视机,打开");
	}

小结:

  1. 高层模块不应该依赖底层模块,二者都应该依赖其(或接口)抽象(不要依赖具体子类)

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

  3. 依赖倒转(倒置)的中心思想是面向接口编程

  4. 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在java中,抽象 指的是接口或抽象类,细节就是具体的实现类

  5. 遵循依赖倒转的话我们在继承时遵循里氏替换原则( 里氏替换原则规定了在任意父类可以出现的地方,子类都一定可以出现 )

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值