控制反转——Spring通过一种称作控制反转(IOC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
下面简单通过实例来看一下控制反转的好处:
首先先定义一个Cat.java类
package com.model; public class Cat { private String name="kitty"; private int age=2; public void sleep(){ System.out.println(name+"猫睡了"); } }
再定义一个main函数的类调用Cat
public class Test { public static void main(String[] args) { Cat p = new Cat(); p.sleep(); }
这样会输出 kitty猫睡了 这句话。
首先我们来分析一下代码:在main中new 一个Cat,其实这样Cat的名字和年龄就已经固定了
重点来了:如果我要换个猫呢?那么new的对象就要从Cat里面修改。这岂不是非常麻烦的事而且破环了项目的一体性。实际上现在工作的控制权并不在main中而是在JavaWork中,而正确的解决方法是将控制权交到mian中!
要想实现控制反转:
首先定义一个接口,让所有的宠物都通过这个接口
package com.model; public interface IPet { public String getName(); public void setName(String name); public void sleep(); }
再将Cat类添加实现方法
package com.model; public class Cat implements IPet { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void sleep(){ System.out.println(name+"猫睡了"); } }
再造一个Dog类实现IPet接口
package com.model; public class Dog implements IPet { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Dog(String name, int age) { super(); this.name = name; this.age = age; } public void sleep(){ System.out.println(name+"狗睡了"); } }
再做一个Human类添加另外一个方法,其中包含了IPet这个接口实现的Cat和Dog类的feed方法
package com.model; public class Human { private IPet pet; public IPet getPet() { return pet; } public void setPet(IPet pet) { this.pet = pet; } public void feed(){ System.out.println("正在喂养"+pet.getName()); pet.sleep(); } }
在这里,我们采用Spring的xml配置来实现控制反转(beans.xml)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="pet1" class="com.model.Dog"> <constructor-arg name="name" value="wang"></constructor-arg> <constructor-arg name="age" value="2"></constructor-arg> </bean> <bean id="pet2" class="com.model.Cat"> <property name="name" value="miao"></property> <property name="age" value="3"></property> </bean> <bean id="pet3" class="com.model.Mouse" init-method="born"> </bean> <bean id="human" class="com.model.Human" > <property name="pet" ref="pet1"></property> </bean> </beans>
最后做一个带有main函数的测试类
package com.model; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { // IPet p = new Dog(); // p.sleep(); ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); IPet p1=(IPet)context.getBean("pet1"); IPet p2=(IPet)context.getBean("pet2"); IPet p3=(IPet)context.getBean("pet3"); p1.sleep(); p2.sleep(); p3.sleep(); Human h = (Human)context.getBean("human"); h.feed(); } }
此时的输出结果为
wang狗睡了
miao猫睡了
laoshu鼠睡了
正在喂养wang
wang狗睡了
因为在beans.xml中定义的pet1狗叫wang年龄2,pet2猫叫miao年龄3,human只喂养了pet1狗,再调用pet1的sleep,然后可以发现,我定义了一个pet3的老鼠,但是我并没有给它名字和年龄,依然能出来结果,是因为调用了init-method="born"方法,这个写法的意思是调用此类内部的方法born,看一下Mouse.java类的写法:
package com.model; public class Mouse implements IPet{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void born(){ name="laoshu"; age=1; } public void sleep(){ System.out.println(name+"鼠睡了"); } }
是不是一目了然。所以如果要换个宠物来养,那么直接修改beans.xml里面human的ref里面的定义的bean的id就好了。