1、new使用离散不易于管理
在理解控制反转之前我们先看一个简单的例子
我们想打印出学生所学习的课程信息,我们有一个课程接口(ICourse),有两门课程HtmlCourse和JavaCourse,如果是以前的话我们会这样写代码
接口ICourse:
public interface ICourse {
//学习的课程
void learn();
}
HtmlCourse.java
public class HtmlCourse implements ICourse {
@Override
public void learn() {
// TODO Auto-generated method stub
System.out.println("学习Html");
}
}
JavaCourse.java
public class JavaCourse implements ICourse {
@Override
public void learn() {
// TODO Auto-generated method stub
System.out.println("学习Java");
}
}
然后会有一个学生类Student:
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sty.factory.CourseFactory;
import com.sty.newinstance.HtmlCourse;
import com.sty.newinstance.ICourse;
import com.sty.newinstance.JavaCourse;
public class Student {
private int stuNo;
private String name;
private String age;
public int getStuNo() {
return stuNo;
}
public void setStuNo(int stuNo) {
this.stuNo = stuNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
//创建对象太麻烦,很离散,加入有很多们课程,就会new很多各对象
//要学习javaClass
public void learnJava() {
ICourse course = new JavaCourse();
course.learn();
}
//要学习htmlClass
public void learnhtml() {
ICourse course = new HtmlCourse();
course.learn();
}
@Override
public String toString() {
return "Student [stuNo=" + stuNo + ", name=" + name + ", age=" + age + "]";
}
}
最后我们在Test里面调用这两个方法打印学生学课信息
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sty.Student;
public class Test {
//最原始的做法,去创建对象,并且里面的每一个方法都是用new的形式,很离散,修改的时候和麻烦,会找到很多的方法
public static void learnCourseNew() {
Student stu = new Student();
stu.learnhtml();
stu.learnJava();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
learnCourseNew();
}
}
最终上面会打印出学习java和学习Html,然而这种方法在上面的注释也提到了,那就是在面对很多课程的时候无疑是很复杂的,不断的new对象,也不方便管理
2、可以创建一个课程工厂(CourseFactory)来帮助我们管理这些new的对象
CourseFactory.java
import com.sty.newinstance.HtmlCourse;
import com.sty.newinstance.ICourse;
import com.sty.newinstance.JavaCourse;
//课程工厂
public class CourseFactory {
public static ICourse getCourse(String name) {
if(name.equals("java")) {
return new JavaCourse();
}else {
return new HtmlCourse();
}
}
}
Test里面创建新的方法在main里面调用
//用一个工厂,将new都放到一个工厂中来实现,修改的时候就只需要找到对应的方法
public static void learnCourseWithFactory() {
Student stu = new Student();
stu.learn("java");
}
Student添加新的方法
//学习任何课程
public void learn(String name) {
ICourse course = CourseFactory.getCourse(name); //course就是根据传入的名字返回具体的课程,然后调用自己课程的学习方法
course.learn();
}
这样就可以根据你传进来的课程值,打印出对应的学习课程而且,有改动的时候,只需要找到这个方法就行。第一中方式,就会找到多个方法进行修改,当方法多的时候,就很费劲。可是在我们的Test里面的learn方法中一句会去new那个新建的工厂,可不可以不用new呢?
3、Spring的IOC容器可以替代这个工厂CourseFactory
在配置好Spring环境后(其实就是在你的java项目添加几个jar包),
spring-aop-4.3.9.RELEASE.jar//开发AOP特性需要用到,
spring-beans-4.3.9.RELEASE.jar//写bean表达式要用到
spring-context-4.3.9.RELEASE.jar//处理spring上下文
spring-core-4.3.9.RELEASE.jar//核心包,Spring工程必须有这个包
spring-expression-4.3.9.RELEASE.jar//Spring表达式(EL)
commons-logging-1.1.1.jar//日志
新建一个Spring bean.xml文件(applicationContext.xml)(右键->other->输入bean(在确保你安装了spring-tools-suite)->选择Spring下的Spring bean Configuration File)
<?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">
<!-- 该文件中的所有对象都在spring容器中 -->
<!-- id唯一标识符 class指定类型 -->
<bean id="student" class="com.sty.Student">
<!-- property属性 -->
<property name="stuNo" value="1"></property>
<property name="name" value="ls"></property>
<property name="age" value="25"></property>
</bean>
<!-- 注入htmlCourse类 -->
<bean id="htmlCourse" class="com.sty.newinstance.HtmlCourse" >
</bean>
<!-- 注入javaCourse类 -->
<bean id="javaCourse" class="com.sty.newinstance.JavaCourse" >
</bean>
</beans>
将Student里面的learn方法修改一下(注意导包)
// 学习任何课程
public void learn(String name) {
/*
* 不需要工厂了 ICourse course = CourseFactory.getCourse(name);
* //course就是根据传入的名字返回具体的课程,然后调用自己课程的学习方法 course.learn();
*/
// 从容器里面拿
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//getBean()方法依据之前注入的id值获取定义的类
ICourse course = (ICourse) context.getBean(name);
// 通过获取到的课程类型在进入各自的学习方法
course.learn();
}
因此Test里面的方法也改变一下
//SPringIOC
public static void learnCourseWithIOC() {
//不需要new对象,也是先通过获取上下文
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC获取学生对象
Student stu = (Student)context.getBean("student");
stu.learn("htmlCourse");//课程名
}
使用第三种方法,我们就可以不使用new的方式获取或者创建对象,并且当你需要修改的时候,只需要修改Test类中learnCourseWithIOC方法传入的课程名
总结:
怎样理解控制反转(IOC):
比如第一种方法,我们不管怎样都要去new对象来实现我们的功能,我们需要设定一些我们想要的东西,比如属性值呀等等,总之必须由你自己来设计。现在就是说Spring有一个容器,你只需要告诉他,你想设置什么值,你以后要用的时候久来取,我先帮你管理着,这时候Spring就充当着你以前的角色,这就是控制反转。
什么又叫依赖注入(DI):
其实DI和IOC可以说是一个意思,只是IOC可能不好理解,我的理解就是,在一个类中你可能会用到其他类怎么办?第一思路就是用new关键字创建一个你需要的类,对吧,可是这样会产生一个叫耦合性的问题:意思就是说,请不要在我自己的类中再去创建其他的类,让我自己能够独立起来,不想与其他类产生关联。
所以解决办法就是使用Spring容器,n我们只需要告诉Spring,这个类会依赖于其他的东西,具体怎么构造,合适构造,由Spring来完成,然后Spring自己会在适当的时候给这个类注入你依赖的东西,这就是依赖注入的由来
以上是本人通过实际课程案例,得出的一些心得,如果由错误或者不够完善的地方,还希望各位大神多多指教,谢谢!!