这几天简单了解学习了Spring框架,其中的IOC(DI)与AOP的特性自然是其精髓所在,正好也在学习设计模式,结合设计模式理解了一下
1.IOC(DI)依赖注入--State模式
依赖注入是什么?首先看一个例子,工程中业务层类(Business)需要调用底层打印类(RealWriter)来完成自己的功能,关系图如下:
Business类的save方法中会调用RealWriter实例的saveToReal方法,即Business类的功能实现依赖RealWriter类,可如果如今我们又多了一种Writer的实现方式,区别于原来的RealWriter类的功能,此时因为Business直接依赖于RealWriter类,我们无法直接使用既有的Business类了,只能大动干戈地修改Business类,这种情况下,IOC(DI)的思想的优势就体现出来了—“程序不应依赖实现,而是依赖于抽象接口”,于是我们把原来的依赖关系修改一下,如下图:
首先我们定义了一个接口Writer并声明了方法saveToWriter,使原先的RealWriter类和新增的OtherWriter类实现这个接口,将原来Business类中定义的具体类实例RealWriter改成接口Writer的声明,并提供Writer的set方法(set方式注入依赖),在save方法逻辑里直接调用接口的saveToWriter方法,这样我们在使用Business的时候就可以通过注入(set方法)不同的实现类RealWriter,OtherWriter来实现自己的功能。这即是IOC的基本概念所在:通过抽象出对象的接口来实现依赖关系的反转,即将控制权从实际的RealWriter类转移至抽象的Writer接口。当然,Spring是通过配置文件来实现依赖注入的引入的,具体这里就不说明了。
IOC的这种实现方式恰好就是状态(State)模式的完整体现,我们例子中得RealWriter和OtherWriter就是两种不同的状态,利用抽象接口实现不同的状态间的相互切换,便于功能扩展和耦合度的减轻。
具体参考代码如下:
Writer.java
public interface Writer {
abstract void saveToWriter();
}
RealWriter.java
public class RealWriter implements Writer {
public void saveToWriter() {
System.out.println("From the RealWriter");
}
}
public class OtherWriter implements Writer {
public void saveToWriter() {
System.out.println("From the OtherWriter");
}
}
public class Business {
private Writer writer;
public void setWriter(Writer writer) {
this.writer = writer;
}
public void save() {
System.out.println("Business--save:begin");
writer.saveToWriter();
System.out.println("Business--save:end");
}
}
2.AOP面向切面--Proxy模式
度娘给的解释是,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面),可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术,我们可以理解为在一个服务的流程中,插入与该服务的业务逻辑无关的系统服务逻辑,如日志、安全认证等等。
例如我们需要在某个已经完成了的类的逻辑出来前后加上log的操作,直接在这个类里面的逻辑里修改是一种方式,却也非常不好,因为加入的东西与逻辑并无关系,而且若有大量的逻辑类需要增加,修改的量很大且容易出错。Spring里通过定义拦截器(interceptor)来实现AOP的功能,定义自己想要的行为插入到预定插入的位置中,这种interceptor的拦截实现大概原理就是Proxy工厂类生产出对象代理,它包含了原对象的处理,插入欲进行的操作并返回,典型的代理(Proxy)模式,用一个关系图来说明一下:
就是在代理类里使用被代理对象的实例,功能方法里调用此实例的方法,并在调用前后添加自己需要的操作,完整满足被代理对象的功能之外完成其他服务的添加。
示例代码如下:
Subject.javaabstract public class Subject {
abstract public void request();
}
public class RealSubject extends Subject {
public RealSubject() {}
public void request() {
System.out.println("From real subject.");
}
}
RealSubject.java
public class ProxySubject extends Subject {
private RealSubject realSubject;
public ProxySubject() {}
public void request() {
preRequest();
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request();
postRequest();
}
private void preRequest() {
System.out.println("do preRequest.");
}
private void postRequest() {
System.out.println("do postRequest.");
}
}
Subject proxySubject = new ProxySubject();
proxySubject.request();