Spring IOC 设计思想解读,由浅入深


一、由new一个对象引发的思考

在正式介绍Spring和IOC前,先看一个案例:

需求:根据不同参数,生成不同形状

思路:

1.创建一个接口,定义一个抽象方法,用于输出不同形状的图形
2.根据创建的接口,实现不同形状的实现类,比如长方形、正方形、圆形等

public interface Shape {
   void draw();
}
public class Rectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
public class Square implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
public class Circle implements Shape {
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

然后我们创建一个main方法,在方法里测试打印不同形状。

public static void main(String[] args){
	Shape circle = new Circle();
	circle.draw();
	//Inside Circle::draw() method.
}

上述代码基本上就是我们最常使用的创建对象的编码方式,简简单单一个new关键字即可搞定。但是产品经理说要新加两个需求。

新需求:
1.把实现类移动到另一个包下
2.新建一个六边形的实现类并打印

这两个需求的解决方式也是十分简单,需求1只需要将调用实现类的方法中实现类的路径改一下即可,需求2只需要新建一个六边形的实现类,并在main方法中更改实现类即可。

但是我们发现,根据需求更改代码虽然容易,但是改动了代码就意味着代码的静态文件发生了变化,若想运行的话必须再对改过的代码重新编译,这也就是代码之间存在耦合的现象,当项目十分庞大时,这种设计思想无疑是十分致命的。

耦合:指代码间的强关联关系,一方改变会影响另一方不得不改变。

具体体现:接口的实现类,硬编码在了程序里。一旦业务需求变更,需要修改实现类,例如new Circle()换成new Square(),则所有调用实现类的代码都要改。

Shape circle = new Circle();

而软件设计的核心思想是高内聚、低耦合,所以我们的解决方案是不符合设计思想的。

二、第一层解耦-----简单工厂设计模式

工厂设计模式的核心思想简单来说就是创建一个工厂类,可以把工厂类理解为一个第三方,将创建对象的动作从调用方法中移植到工厂中创建,再通过工厂类的静态方法得到创建出来的对象。

class factory {
    public static Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
public static void main(String[] args){
	Shape circle = factory.getShape("CIRCLE");
}

以上就是一个最简单的工厂设计模式思想体现,在该思想下,main函数和实现类间解除了耦合,即改变实现类,不会影响main方法中的代码,所以当程序更新时,main函数无需重新编译。

细心的读者可能会发现,虽然解除了main函数和实现类之间的耦合,但是在工厂类中还是存在new一个实现类,也就是说工厂类和实现类间产生了耦合。

二、第二层解耦-----反射创建对象

创建对象有两种方式:

  1. 直接调用构造方法,new一个对象。
Shape circle = new Circle();
  1. 通过反射创建对象
//获取实现类的Class对象
Class clazz = Class.forName("com.hou.basic.Circle");
//根据Class对象实例出实现类对象
Shape circle = (Shape) clazz.newInstance;

既然new一个对象的创建对象方式会带来耦合的问题,那么我们尝试通过反射的方式创建对象,看是否能解除耦合。

显然,通过反射的方式创建对象不得不提供实现类的全限定名,当我们修改实现类路径后,工厂类代码还是要变动,再运行还是需要重新编译,所以我们得出结论:使用反射创建对象仍然是无法完全解耦的。

但是不得不说,使用反射的方式创建对象是Spring IOC思想实现解耦的迈出的极其重要的一步,具体为何,请看下文。

四、终极解耦-----xml配置文件的引入

上文提到通过反射方式创建对象仍然存在耦合的原因是代码依赖了实现类的全限定名。那么能不能像JDBC一样通过配置文件的方式,将实现类的全限定名从代码中移到配置文件中呢?

基于这个思想,Spring引入了xml配置文件,通过键值对的方式存储着实现类的全限定名和id值。

<bean id="circle" class="com.hou.basic.Circle'/>

显然,通过类的id值便可获得类的全限定名,通过全限定名便可采用反射的方式创建对象。

以上就是IOC设计的核心思想,简单总结来说就是:

工厂设计模式 + 反射创建对象 + xml配置文件

具体Spring读取配置文件等代码就不具体展开了。

我们将类的全限定名封装在了配置文件中,那么如果想修改实现类,即修改配置文件时,是否存在耦合导致程序需要重新编译呢?
答案是否定的,配置文件是不需要编译成.class文件的,所以即使修改配置文件,也不会导致配置文件重新编译,即配置文件和实现类间是不存在耦合关系的。那么整个程序就没有存在耦合的地方了。

总结

经过三层解耦方式,我们得到了最终完全解耦的程序,也就是IOC(Inverse of control 反转控制)的核心思想,那么我们再回头看文章开头处由新需求带来的问题是否被解决。

新需求:
1.把实现类移动到另一个包下
2.新建一个六边形的实现类并打印

分析:

***需求1:***移动实现类更改的是实现类的全限定名,在IOC模式下,需要修改的就是配置文件中类的全限定名,在调用程序中使用的是类的id值,也就是说该新需求是不需要改变程序文件的,所以是完全解耦、更改后不需要重新编译的设计思想。

***需求2:***同理我们新建一个实现类,在配置文件中修改类的全限定名,而全限定名对应的键id是不变的,即源程序依然没有任何改动,更改后不需要重新编译。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值