Spring中的设计模式
1. 设计模式
设计模式(Design pattern)是解决一类问题的通用设计解决方案。
共有23种设计模式,分为三大类——创建型设计模式、结构型设计模式和行为型设计模式。
Spring中常用的设计模式有九种。
2.第一种 简单工厂
又叫静态工厂方法模式,不属于23种模式之一,其实质是由一个工厂类根据传入的参数来动态决定应该创建哪一个产品类。它是创建型模式。
Spring中的BeanFactory就是简单工厂模式,根据传入一个唯一的标识来获得Bean对象,但是否在传入参数后创建还是传入之前创建这个要根据具体情况来定。
<!--在Hello类中创建一个ABean --> <beans> <bean id="singletonBean" class="com.itxxz.Hello"> <constructor-arg> <value>Hello! 这是singletonBean!</value> </constructor-arg> </bean> <bean id="ABean" class="com.itxxz.Hello" singleton="false"> <constructor-arg> <value>Hello! 这是ABean! value> </constructor-arg> </bean> </beans>
设计意义:
松耦合。可以将原来硬编码的依赖,通过Spring这个beanFactory这个工长来注入依赖,也就是说原来只有依赖方和被依赖方,现在我们引入了第三方——spring这个beanFactory,由它来解决bean之间的依赖问题,达到了松耦合的效果.
bean的额外处理。通过Spring接口的暴露,在实例化bean的阶段我们可以进行一些额外的处理,这些额外的处理只需要让bean实现对应的接口即可,那么spring就会在bean的生命周期调用我们实现的接口来处理该bean。
3.第二种 工厂方法
通常应用程序直接用new来创建实例,为了将实例化与使用相分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象。它是创建型模式。
一般情况下,应用程序有自己的工厂对象来创建bean,如果将应用程序自己的工厂对象交给Spring管理,那么spring管理的就不是普通的bean,而是工厂bean。
以工厂方法中的静态方法为例:
import java.util.Random; public class StaticFactoryBean { public static Integer createRandom() { return new Integer(new Random().nextInt()); } }
建立一个config.xml配置文件,将其纳入spring容器来管理,需要通过factory-method指定静态方法名称
<bean id="random" class="example.chapter3.StaticFactoryBean" factory-method="createRandom" scope="prototype" <!-- createRandom方法必须是static的,才能找到--> />
测试:
public static void main(String[] args) { //调用getBean()时,返回随机数.如果没有指定factory-method,会返回StaticFactoryBean的实例,即返回工厂Bean的实例 XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("config.xml")); System.out.println("我是IT学习者创建的实例:"+factory.getBean("random").toString()); }
4.第三种 单例模式
单例模式是保证一个类仅有一个实例,并提供一个访问它的全局访问点。它是创建型模式。
单例模式的创建需要考虑性能、线程安全与否、是否防破解、是否按需加载
有四种:
懒汉式:按需加载、但是线程不安全
饿汉式:线程安全、但是占用资源,不按需加载
同步锁:线程安全、按需加载、但是性能不高,需要加锁和释放锁的资源消耗
静态内部类:
不放破解的静态内部类,线程安全、按需加载、性能高,但是可能出现两个单例。
防破解的静态内部类,抛出运行时异常,线程安全、按需加载、性能高、且防破解。
Spring中的单例模式即提供了全局的访问点BeanFactory,但是没有从构造器级别去控制单例,这是因为Spring管理的是任意的java对象。
Spring下默认的 bean均为 singleton,可以通过 singleton=“true/false” 或者 scope=“?”来指定
5.第四种 适配器模式
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。它是结构型模式,它结合了两个独立接口的功能。
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
在Spring的面向切面编程(AOP,Aspect Oriented Programming)中,使用的Advice(通知)来增强被代理类的功能。
Spring实现这一AOP功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)对类进行方法级别的切面增强,即生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器重的内容增强了代理方法的功能,实现的面向切面编程。
//Adapter类接口:Target public interface AdvisorAdapter { boolean supportsAdvice(Advice advice); MethodInterceptor getInterceptor(Advisor advisor); } //MethodBeforeAdviceAdapter类,Adapter class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { public boolean supportsAdvice(Advice advice) { return (advice instanceof MethodBeforeAdvice); } public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); } }
实现意义:Spring定义了一个适配接口,使得每一种Controller有一种对应的适配器实现类,让适配器代替controller执行相应的方法。这样在扩展Controller时,只需要增加一个适配器类就完成了SpringMVC的扩展了。
6.第五种 装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。它是结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
目的:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
在传统Spring中的持久层,我们总是去配置一个数据源,因此sessionFactory的DataSource属性总是一个固定的数据源,但是我们想在持久层中拿到不同数据源的数据,即根据用户需求动态的切换不同的数据源。
首先想到在spring的applicationContext中配置所有的dataSource。这些dataSource可能是各种不同类型的,比如不同的数据库:Oracle、SQL Server、MySQL等,也可能是不同的数据源:比如apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等。
然后sessionFactory根据客户的每次请求,将dataSource属性设置成不同的数据源,以到达切换数据源的目的。其中对数据库的操作都是增删改查,但是整体的包装却切换了数据库。
spring中用到的装饰器模式在类名上有两种表现:
一种是类名中含有Wrapper;
另一种是类名中含有Decorator。
基本上都是动态地给一个对象添加一些额外的职责。
7.第六种 代理模式
代理模式(Proxy Pattern)中,一个类代表另一个类的功能。就是原本自己要做的事情,让别人来代替自己做。它是结构型模式。
目的:为其他对象提供一种代理以控制这个对象的访问。
注意事项:
和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
Spring中的代理模式在AOP中体现,如JdkDynamicAopProxy和Cglib2AopProxy。
8.第七种 观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。它是行为型模式。
目的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
Spring中Observer模式常用的地方是listener的实现。如ApplicationListener。
ApplicationListener接口(事件监听器)
继承自jdk的EventListener,所有的监听器都要实现这个接口。
这个接口只有一个onApplicationEvent()方法,该方法接受一个ApplicationEvent或其子类对象作为参数,在方法体中,可以通过不同对Event类的判断来进行相应的处理。
当事件触发时所有的监听器都会收到消息。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E event); }
9.第八种 策略模式
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。它是行为型模式。
目的:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
Spring中在实例化对象的时候用到Strategy模式,这种模式应该是最能体会到的,在每次实例化对象的时候去执行的方法是可变的,把这些可变的部分抽象成接口,再基于接口编程各种功能,让对象在不同的行为中选择一种行为。
实现方式:Spring框架的资源访问Resource接口 。该接口提供了更强的资源访问能力,Spring 框架本身大量使用了 Resource 接口来访问底层资源。
Resource 接口介绍
source 接口是具体资源访问策略的抽象,也是所有资源访问类所实现的接口。
Resource 接口主要提供了如下几个方法:
getInputStream():定位并打开资源,返回资源对应的输入流。每次调用都返回新的输入流。调用者必须负责关闭输入流。
exists():返回 Resource 所指向的资源是否存在。
isOpen():返回资源文件是否打开,如果资源文件不能多次读取,每次读取结束应该显式关闭,以防止资源泄漏。
getDescription():返回资源的描述信息,通常用于资源处理出错时输出该信息,通常是全限定文件名或实际 URL。
getFile:返回资源对应的 File 对象。
getURL:返回资源对应的 URL 对象。
最后两个方法通常无须使用,仅在通过简单方式访问无法实现时,Resource 提供传统的资源访问的功能。
Resource 接口本身没有提供访问任何底层资源的实现逻辑,针对不同的底层资源,Spring 将会提供不同的 Resource 实现类,不同的实现类负责不同的资源访问逻辑。
Spring 为 Resource 接口提供了如下实现类:
UrlResource:访问网络资源的实现类。
ClassPathResource:访问类加载路径里资源的实现类。
FileSystemResource:访问文件系统里资源的实现类。
ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类.
InputStreamResource:访问输入流资源的实现类。
ByteArrayResource:访问字节数组资源的实现类。
这些 Resource 实现类,针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装,以利于客户端程序的资源访问。
10.第九种 模板方法模式
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。它是行为型模式。
目的:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
Template Method模式一般是需要继承的。
Spring中的JdbcTemplate,在用这个类时并不想去继承这个类。
为什么JdbcTemplate没有使用继承?
因为这个类的方法太多,但是我们还是想用到JdbcTemplate已有的稳定的、公用的数据库连接,那么我们怎么办呢?我们可以把变化的东西抽出来作为一个参数传入JdbcTemplate的方法中。但是变化的东西是一段代码,而且这段代码会用到JdbcTemplate中的变量。怎么办?那我们就用回调对象吧。在这个回调对象中定义一个操纵JdbcTemplate中变量的方法,我们去实现这个方法,就把变化的东西集中到这里了。然后我们再传入这个回调对象到JdbcTemplate,从而完成了调用。
模板方法模式与工厂方法模式的区别:由于看到这里觉得这两个模式非常的像,所以去搜了搜他们之间的区别。
工厂方法模式:是类的创建模式,又叫做虚拟构造子模式或者多态性工厂模式。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
模板方法模式:是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的构造子类可以以不同的方法实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。
模板方式和工厂模式的核心思想非常类似, 都是把一些操作留给子类去实现。
模板方法中常常会调用工厂方法的, 他们之间存在着的紧密的情侣关系。
工厂方法模式和模板方法模式的区别在于:
模板方法模式的意义在于固定了一个算法的整体结构, 复用了其中通用的步骤, 将需要定制的部分留给了子类实现
工厂方法模式的意义在于解决了父类没有办法预知应该实现什么子类的问题
在转载基础上添加了些自己的东西,不知是否正解,还在学习过程中......
Spring 模式转载出处,文章首发于:http://itxxz.com/a/javashili/tuozhan/2014/0601/7.html
部分本文来自 iCoding91 的CSDN 博客 ,
全文地址请点击:https://blog.csdn.net/caoxiaohong1005/article/details/80039656?utm_source=copy
部分本文来自 萧萧冷 的CSDN 博客 ,
全文地址请点击:https://blog.csdn.net/lengxiao1993/article/details/59114818?utm_source=copy
设计模式参考:http://www.runoob.com/design-pattern/design-pattern-tutorial.html