99%开发者都在项目中使用过依赖注入,但是没有意识到,那么什么是 依赖注入呢?
1. 举个例子
以手机为例,我们知道,手机需要插入SIM卡才可以正常的拨打电话,也就是说,手机的通话功能依赖于SIM卡。
1.1 不使用依赖注入的代码实现
这里新建SimCard类和MobilePhone类,如下:
class SimCard{
private val TAG = "SimCard"
fun dialNumber()
{
log.d(TAG,"拨打电话")
}
}
class MobilePhone{
fun diaNumber()
{
val simCard = SimCard()
simCard.dialNumber()
}
}
使用MobilePhone类中的拨打电话方法,如下:
val mobilePhone = MobilePhone()
mobile.dialNumber()
1.1.1 解释说明
通过前面的代码可以知道,当调用MobilePhone的dialNumber方法时,首先会在MobilePhone类的dialNumber方法中创建SimCard对象,然后会调用SimCard对象的dialNumber方法。
在这种实现方式中,MobilePhone 类虽然依赖SimCard类,使用依赖类是由MobilePhone类的方法自己创建的。
1.2 使用依赖注入的实现
很简单,SimCard类保持不变,修改MobilePhone的dialNumber方法,传入一个SimCard对象。
class SimCard{
private val TAG = "SimCard"
fun dialNumber()
{
log.d(TAG,"拨打电话")
}
}
class MobilePhone{
fun dialNumber(simCard: SimCard)
simCard.dialNumber()
}
}
使用MobilePhone类中的拨打电话方法,如下:
val mobilePhone = MobilePhone()
val simCard = SimCard()
mobilePhone.dialNumber(simCard)
1.2.1 解释说明
上述代码中,我们创建论mobilePhone对象和simCard对象,并将simCard对象传递给给mobilePhone对象的dialNumber方法,这种实现方式就是依赖注入。
2. 依赖注入的定义
一个类中使用依赖类,这个依赖类不是由使用它的类
创建的,而是通过构造函数或者属性方法传入的。
3. 使用依赖注入由什么好处呢?
在不使用依赖注入的实现中,MobilePhone类不仅要负责自身类的功能,还要负责创建SimCard类的对象。使用依赖注入不仅仅可以提高代码的可扩展性,还可以分离依赖项目。
扩展性体现在哪里呢?
我们假设为不同的运行商的SIM卡创建不同的类,这些类都以SimCard为基类。
假设有 中国移动,中国联通,中国电信 三种SIM卡。
class SimCard{
private val TAG = "SimCard"
fun dialNumber()
{
log.d(TAG,"拨打电话")
}
}
class ChinaMobile:SimCard
{
@override fun dialNumber()
{
log.d(TAG,"中国移动拨打电话")
}
}
class ChinaUnicom:SimCard
{
@override fun dialNumber()
{
log.d(TAG,"中国联通拨打电话")
}
}
class ChinaTelecom:SimCard
{
@override fun dialNumber()
{
log.d(TAG,"中国电信拨打电话")
}
}
假设现在MobilePhone 支持中国移动的卡。
class MobilePhone{
fun diaNumber()
{
val simCard = ChinaMobile()
simCard.dialNumber()
}
}
现在要支持中国联通和中国电信的SIM卡。
不使用依赖注入的话,需要修改MobilePhone的代码,在MobilePhone 的dialNumber方法为不同的卡创建不同实例。
class MobilePhone{
fun dialNumber(cardType:String)
{
if(cardType == "ChinaMobile")
{
val simCard = ChinaMobile()
simCard.dialNumber()
}
else if(cardType == "ChinaUnicom")
{
val simCard = ChinaUnicom()
simCard.dialNumber()
}
else if(cardType == "ChinaTelecom")
{
val simCard = ChinaTelecom()
simCard.dialNumber()
}
}
}
//使用时
val mobiePhone = MobilePhone()
mobiePhone.dialNumber("ChinaMobile")
mobiePhone.dialNumber("ChinaUnicom")
mobiePhone.dialNumber("ChinaTelecom")
由于dialNumber本身并不是mobilePhone来实现的,但是为了增加对不同SIM卡的支持需要修改mobilePhone的代码。
如果使用依赖注入的话,我们就不必修改MobilePhone中的dialNumber方法了,直接传入不同运行商的SIM卡对象即可。
class MobilePhone{
fun dialNumber(simCard: SimCard)
{
val simCard = ChinaTelecom()
simCard.dialNumber()
}
}
//使用时
val mobiePhone = MobilePhone()
val chinaMobile = ChinaMobile()
val chinaUnicom= ChinaUnicom()
val chinaTelecom= ChinaTelecom()
mobiePhone.dialNumber(chinaMobile )
mobiePhone.dialNumber(chinaUnicom)
mobiePhone.dialNumber(chinaTelecom)
这样,MobilePhone类增加对新的SIM卡的支持,就不需要修改MobilePhone类的代码了,只需要给SimCard类增加新的子类即可。
不使用依赖注入的写法,违反了开闭原则,即:一个类,对扩展是开放的,对修改是封闭的。增加新功能,不应该修改现有的方法。