Head First设计模式学习
策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换。此模式让算法的变化独立于使用算法的客户。(P24,Spring中在实例化对象的时候用到Strategy模式)。
观察者模式:定义了对象间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。(P51,spring中Observer模式常用的地方是listener的实现。如ContextLoaderListener、ApplicationListener)
装饰者模式:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。(P91,100)Spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责,比如BeanWrapper,它的实现类BeanWrapperImpl的setPropertyValue(PropertyValue pv)方法可以为Bean的属性实现依赖注入。
工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。(P134)Spring中的FactoryBean就是典型的工厂方法模式,由其子类如ProxyFactoryBean、TransactionProxyFactoryBean的getObject()方法返回生成的具体类。
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。(P156)
单例模式:保证一个类只有一个实例,并提供一个全局访问点。(P177)Spring中的TruePointcut、TrueMethodMatcher类实现了一个单例。
命令模式:将请求封装成对象,这可以让你使用不同的请求、队列,或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式。(P206,230)
适配器模式:将一个类的接口,装换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。如Spring中的MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter(P243)
外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。(P264)
模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。如Spring中的AbstractPlatformTransactionManager的事务的生成getTransaction、事务的挂起suspend、事务的提交commit、事务的回滚rollback都是模板方法(P289)
迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。可实现java.util.Iterator接口。(P336)
组合模式:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象及对象组合。(P356)
状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。(P410)
代理模式:为另一个对象提供一个替身或占位符以控制对这个对象的访问。Spring动态代理类JdkDynamicAopProxy和Cglib2AopProxy(P460)
MVC模式:一个复合模式,把一个应用分成三个截然不同的组件:模型、视图、控制器,实现系统解耦,保持设计干净又有弹性。控制器是视图的策略,视图可以使用不同的控制器实现,得到不同的行为。具体实现如Spring MVC(P532,560)
Spring中的设计模式:
策略模式:Spring中在实例化对象的时候用到Strategy模式,下面是SimpleInstantiationStrategy的instantiate方法,要么使用JDK的反射功能根据构造器生成实例,要么使用Cglib来生成实例,Cglib实例化具体在类CglibSubclassingInstantiationStrategy的instantiate方法里。
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
final Constructor<?> ctor, Object[] args) {
//判断Bean是否有方法被覆盖,如果没有则用JDK的构造器实例化,否则用Cglib来实例化
if (beanDefinition.getMethodOverrides().isEmpty()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
ReflectionUtils.makeAccessible(ctor);
return null;
}
});
}
return BeanUtils.instantiateClass(ctor, args); //使用JDK的反射功能根据构造器生成实例:ctor.newInstance(args)
} else { //使用Cglib来生成实例:enhancer.create()
return instantiateWithMethodInjection(beanDefinition, beanName, owner, ctor, args);
}
}
模板方法模式:
1.AbstractRefreshableApplicationContext的refreshBeanFactory方法里定义了一些流程,它自己的loadBeanDefinitions是一个protected abstract方法,其子类XmlWebApplicationContext和AnnotationConfigWebApplicationContext分别有自己的实现,这是一个模板方法模式。
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
2.DefaultResourceLoader里定义了方法getResourceByPath,是为读取Resource服务的,在getResource(String location)里调用了这个方法,并定义了方法的处理流程:它先会处理带有classpath标识的Resource,再处理URL标识的资源定位,如果既不是classpath,也不是URL标识的资源定位,则把getResource的任务交给getResourceByPath方法,这个一个protected的方法,默认返回一个ClassPathContextResource。
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
if (location.startsWith(CLASSPATH_URL_PREFIX)) { //处理带有classpath标识的Resource
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
} else {
try {
//再处理URL标识的资源定位
URL url = new URL(location);
return new UrlResource(url);
} catch (MalformedURLException ex) {
//如果既不是classpath,也不是URL标识的资源定位,则把getResource的任务交给getResourceByPath方法
return getResourceByPath(location);
}
}
}
protected Resource getResourceByPath(String path) {
return new ClassPathContextResource(path, getClassLoader());
}
子类FileSystemXmlApplicationContext覆盖了方法getResourceByPath(String path),返回FileSystemResource。
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
子类ServletContextResourceLoader覆盖了这个方法,返回ServletContextResource。
@Override
protected Resource getResourceByPath(String path) {
return new ServletContextResource(this.servletContext, path);
}
子类重新定义了getResourceByPath方法,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
3.AbstractPlatformTransactionManager的事务的生成方法getTransaction、事务的挂起suspend、事务的提交commit、事务的回滚rollback都是模板方法,由像DataSourceTransactionManager或HibernateTransactionManager这样的具体事务处理器来实现。
单例模式:Spring中的TruePointcut类实现了一个单例,在接口Pointcut中持有这个引用,Pointcut TRUE = TruePointcut.INSTANCE;
类似的单例类还有TrueMethodMatcher.
package org.springframework.aop;
import java.io.Serializable;
class TruePointcut implements Pointcut, Serializable {
public static final TruePointcut INSTANCE = new TruePointcut();
/**
* Enforce Singleton pattern.
*/
private TruePointcut() {
}
}