控制反转和依赖注入
标签(空格分隔): java基础知识
控制反转(Inversion of Control,IOC)
在了解控制反转之前,先看下什么是控制正转。
控制正转
当我们在一个系统中,需要两个或两个以上的类协助工作时,我们通常会在一个入口类中使用new关键字来创建另一个类的实例。
这就好比 我每次吃饭的时候都需要自己主动的去买一双一次性筷子(每次使用前都需要new一个),此时的我(相当于调用者)每次都需要主动的去买一双筷子(new 一个其他类的实例) ,这时候是我控制了筷子的产生。
控制反转
而控制反转就好比,突然有一天你不想再去每次吃饭都买筷子了,于是,你自己买了一双筷子,并把它放在一个自动出筷机中(IOC容器),你需要使用的时候就把手伸出去跟这个容器说:IOC容器啊,我想用筷子(向IOC容器发出请求),接着筷子就会自动弹出(注入)到你的手上。
这个过程中,你不再是控制筷子产生的控制方,反而你成为了一名请求者(虽然本身还是调用者)
依赖于IOC容器(自动出筷机)给予你所需的资源(筷子),这时候控制筷子“产生”的控制权坐落到了容器身上,这就是人们俗称的控制反转。
总结
所谓的控制 通俗的来说就是控制资源产生的控制权,而“反转”则代表原本需要由入口类控制的产生权转移到了容器上。
综合来说,控制反转即依赖对象的获得被反转了。如果这个获取过程要靠自身实现,那么这将导致代码高度耦合并且难以维护和调试。
结合下图 我们可以看下筷子是怎么在IOC思想下来到我们手上的(即我们是如何获得请求的类),其实这就是一个依赖注入的过程。
依赖注入
说完控制反转,再来说依赖注入
好莱坞原则
-
在设计原则中有一个”好莱坞原则”即
- “别找我们,我们找你”
在好莱坞中,艺人把简历交给演艺公司后只能回家等待公司的通知而不能自己去询问公司,只有在公司需要你的时候,通知你出现你才能出现。
所以 好莱坞原则的核心是以通知代替轮询
依赖注入深入浅出
依赖注入的几种实现方式
最常用的两种
1 属性注入
.class文件
public class Car {
public String brand;
private String corp;
private double price;
private int maxSpeed;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String toString(){
return "brand:"+brand+"/maxSpeed:"+maxSpeed+"/price:"+price;
}
}
public class DiTypeTest {
public ApplicationContext factory = null;
private static String[] CONFIG_FILES = { "com/smart/ditype/beans.xml" };
@BeforeClass
public void setUp() throws Exception {
factory = new ClassPathXmlApplicationContext(CONFIG_FILES);
}
@Test
public void testCar(){
Car car = (Car)factory.getBean("car");
assertNotNull(car);
System.out.println(car);
}
}
----------
配置文件
<!-- 属性注入 -->
<!--bean id="car" class="com.smart.ditype.Car">
<property name="brand" value="红旗&CA72"/>
<property name="maxSpeed" value="200"/>
<property name="price" value="20000.00"/>
</bean>
2 构造函数注入
.class文件
public class Car {
public String brand;
private String corp;
private double price;
private int maxSpeed;
public Car() {}
public Car(String brand, double price) {
this.brand = brand;
this.price = price;
}
public Car(String brand, String corp, double price) {
this.brand = brand;
this.corp = corp;
this.price = price;
}
public Car(String brand, String corp, int maxSpeed) {
this.brand = brand;
this.corp = corp;
this.maxSpeed = maxSpeed;
}
}
@Test
public void testCar1(){
Car car1 = (Car)factory.getBean("car1");
assertNotNull(car1);
System.out.println(car1);
}
----
配置文件
<!--构造函数注入:type -->
<bean id="car1" class="com.smart.ditype.Car">
<constructor-arg type="java.lang.String">
<value>红旗CCCA72</value>
</constructor-arg>
<constructor-arg type="double">
<value>10000</value>
</constructor-arg>
</bean>
以及 工厂注入
public class CarFactory {
public Car createHongQiCar(){
Car car = new Car();
car.setBrand("红旗CA72");
return car;
}
public static Car createCar(){
Car car = new Car();
return car;
}
}
@Test
public void testCar5(){
Car car5 = (Car)factory.getBean("car5");
assertNotNull(car5);
System.out.println("car5:"+car5);
}
@Test
public void testCar6(){
Car car6 = (Car)factory.getBean("car6");
assertNotNull(car6);
System.out.println("car6:"+car6);
}
---
<!-- 工厂方法-->
<bean id="carFactory" class="com.smart.ditype.CarFactory" />
<bean id="car5" factory-bean="carFactory" factory-method="createHongQiCar">
</bean>
<bean id="car6" class="com.smart.ditype.CarFactory"
factory-method="createCar"></bean>