简单的IOC实现

IOC简介:
IOC:Inversion of Control,控制反转,它最主要反映的是与传统面向对象(OO)编程的不同。了解IOC需要注意的是:1.谁控制谁 2.反转了什么
也可以理解成:Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。
采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定

实现方式:
实现数据访问层
数据访问层有两个目标。第一是将数据库引擎从应用中抽象出来,这样就可以随时改变数据库—比方说,从微软SQL变成Oracle。不过在实践上很少会这么做,也没有足够的理由和能力去通过使用实现数据访问层而对现有的应用进行重构。
第二个目标是将数据模型从数据库实现中抽象出来。这使得数据库或代码开源根据需要改变,同时只会影响主应用的一小部分——数据访问层。这一目标是值得的,为了在现有系统中实现它进行必要的重构。

模块与接口重构
依赖注入背后的一个核心思想是单一功能原则(single responsibility principle)。该原则指出,每一个对象应该有一个特定的目的,而应用需要利用这一目的的不同部分应当使用合适的对象。这意味着这些对象在系统的任何地方都可以重用。但在现有系统里面很多时候都不是这样的。

随时增加单元测试
把功能封装到整个对象里面会导致自动测试困难或者不可能。将模块和接口与特定对象隔离,以这种方式重构可以执行更先进的单元测试。按照后面再增加测试的想法继续重构模块是诱惑力的,但这是错误的。

使用服务定位器而不是构造注入
实现控制反转不止一种方法。最常见的办法是使用构造注入,这需要在对象首次被创建时提供所有的软件依赖。然而,构造注入要假设整个系统都使用这一模式,这意味着整个系统必须同时进行重构。这很困难、有风险,且耗时。

举个例子……
以前吃饭要自己做,后来可以点外卖,自己不用做也可以有饭吃,只要在上面点这道菜,就会帮你做好,并且直接送到家。以前是自己动手做饭,现在是别人做饭,这个角色变化,就是对“饭”的控制由你反转到了别人。类比过来就是,对对象的控制由程序反转到了框架。还以做饭为例,可以炒饭、可以炒菜,所以我们会抽象出一个接口:

public interface CookMeal()
	void cook();
}

之后:

public class FiredRice implement CookMeal{
@Override
void cook(){
// 炒饭
	}
}
public class  StirFry implement CookMeal{
	@Override
	void cook(){
		// 炒菜
	}
}

比如有个类A先是酱油炒饭:

public class A {
	CookMeal cookMeal = new SoyRice();
	cookMeal.cook();
}

然后改成扬州炒饭,那么需要改A这个类:

public class A {
	//CookMeal cookMeal = new SoyRice();
	CookMeal cookMeal = new  YangzhouRice();
	cookMeal.cook();
}

如果还有其他做法呢?还是得改这个类。再接着,如果类A中的SoyRice希望有个属性叫RiceType标志使用哪种米做

public class SoyRice implement CookMeal{
	RiceType riceType;
	public SoyRice(RiceType riceType){
		this.riceType = riceType;
	}
	@Override
	void cook(){
	}
}

那么类A又要改:

public class A {
	//CookMeal cookMeal = new SoyRice();
	CookMeal cookMeal = new SoyRice(riceType Type);
	cookMeal.cook();
}

如果现在有其他的类如A1、A2、A3…都像这样开始不需要构造入参,当SoyRice改动的时候,所有持有SoyRice依赖的类全都要改动。但是其实classA只关心自己的业务代码(例子中的cook方法),并不关心到底是该怎么构造实例,炒饭用什么米都可,但是classA只关心“cook”。可能你只是想改一下米的类型,但是却不得不对很多涉及到具体业务的类作出改动。这很麻烦,也很危险,因为不知道在n多个其他的类里这个改动会不会有影响。究其原因,是CookMeal的生成(new的动作)是由A控制的,而IOC的思想就是,生成CookMeal由框架去做。类A只需要关心cook这件事(业务逻辑)就好了,生成饭的逻辑的都由框架去做。

总结
反射的方式是在启动的时候生成对象,
优点:应用一启动,所有配置的类的对象都会生成,生命周期 = 应用生命周期;
缺点:适合服务端,不适合移动端。xml放在app不安全、解析会导致启动慢、反射耗性能、静态HashMap会内存泄漏。

new 对象的方式是在编译时生成一行“new XXX()“,运行时调用。
优点:编译时生成代码,使用时才生成对象,资源代价小。
缺点:对框架的要求高(生成代码很繁琐,想要更易用也需要做很多工作)。

不管哪种方式,IOC的都是通过一个映射关系生成对象,而上述两者的本质是:
xml是将这种映射关系维系在了静态文件中,new 对象的方式是将这种映射关系维系在了注解和被注解的对象(本质上是class 和 method这种调用关系)中,只有在运行时才会知道要生成的是什么。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值