在我们的日常开发中,创建对象的操作随处可见以至于对其十分熟悉的同时又感觉十分繁琐,每次需要对象都需要亲手将其new出来,甚至某些情况下由于坏编程习惯还会造成对象无法被回收,这是相当糟糕的。但更为严重的是,我们一直倡导的松耦合,少入侵原则,这种情况下变得一无是处。于是前辈们开始谋求改变这种编程陋习,考虑如何使用编码更加解耦合,由此而来的解决方案是面向接口的编程,于是便有了如下写法:
UserServiceImpl类中由原来直接与UserDaoImp打交互变为UserDao,即使UserDao最终实现依然是UserDaoImp,这样的做的好处是显而易见的,所有调用都通过接口userDao来完成,而接口的真正的实现者和最终的执行者就是UserDaoImpl,当替换UserDaoImpl类,也只需修改userDao指向新的实现类。
虽然上述的代码在很大程度上降低了代码的耦合度,但是代码依旧存在入侵性和一定程度的耦合性,比如在修改UserDao的实现类时,仍然需求修改UserServiceImpl的内部代码,当依赖的类多起来时,查找和修改的过程也会显得相当糟糕。
所以工厂设计模式,又被提了出来,我们把这种有可能变化的部分,放到Dao层的工厂类里,UserDao是实现类变了,我就对应修改Dao里的工厂类里对象的方法,这样就不用修改UserServiceImpl类的内部代码了!
虽然上述的代码进一步地降低了代码的耦合度,但是代码依旧存在入侵性和一定程度的耦合性,那就是UserServiceImpl类和Dao层里的工厂类之间,仍然耦合着, 修改工厂类后,UserServiceImpl就得跟着改,所以呢, 前辈们继续考虑着.......
Rod Johnson
Rod Johnson提出了控制反转IOC和依赖注入DI的概念:
这种方法如我们所愿生成了userDao的实例,这样做的好处是在有替换userDao实现类的情况只需修改配置文件的内容而无需触及UserServiceImpl的内部代码,从而把代码修改的过程转到配置文件中,相当于UserServiceImpl及其内部的userDao通过配置文件与UserDao的实现类进行关联,这样UserServiceImpl与UserDao的实现类UserDaoImpl间也就实现了解耦合,当然UserServiceImpl类中存在着UserDao对象是无法避免的,毕竟这是协同工作的基础,我们只能最大程度去解耦合。
这里我提出了一个新的概念依赖注入:所谓的依赖注入,其实是当一个bean实例引用到了另外一个bean实例时spring容器帮助我们创建依赖bean实例并注入(传递)到另一个bean中,如上述案例中的UserServiceImpl类依赖于UserDao的实现类UserDaoImpl,Spring容器会在创建UserService的实现类和UserDao的实现类后,把UserDao的实现类注入UserService实例中。