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() { } }