Spring圆满设计:Resource接口与策略模式

Spring完美设计:Resource接口与策略模式

不管是资源(Resource),还是资源加载器(ResourceLoader),Spring都把它定义成了接口的形式,而不是类的形式。这样降低了与具体的实现类之间的耦合,更具灵活性与易扩展性。它们的关系图如下:

 


Spring圆满设计:Resource接口与策略模式
 

且看ResourceLoader的getResource(String location)方法的声明:

	/**
	 * Return a Resource handle for the specified resource.
	 * The handle should always be a reusable resource descriptor,
	 * allowing for multiple {@link Resource#getInputStream()} calls.
	 * <p><ul>
	 * <li>Must support fully qualified URLs, e.g. "file:C:/test.dat".
	 * <li>Must support classpath pseudo-URLs, e.g. "classpath:test.dat".
	 * <li>Should support relative file paths, e.g. "WEB-INF/test.dat".
	 * (This will be implementation-specific, typically provided by an
	 * ApplicationContext implementation.)
	 * </ul>
	 * <p>Note that a Resource handle does not imply an existing resource;
	 * you need to invoke {@link Resource#exists} to check for existence.
	 * @param location the resource location
	 * @return a corresponding Resource handle
	 * @see #CLASSPATH_URL_PREFIX
	 * @see org.springframework.core.io.Resource#exists
	 * @see org.springframework.core.io.Resource#getInputStream
	 */
	Resource getResource(String location);

接口的声明,要求location的格式能满足多形式,也就是要支持多种类型的Resource。上面的类关系图中,我们就可看出有两种Resource,分别是UrlResource和ClasspathResource,前者是加载URL指定的资源,后者是加载类路径中的资源。

我们来看看Spring实现类DefaultResourceLoader中是如何用一个接口方法加载两种资源的:

 

	public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");
		if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
			try {
				// Try to parse the location as a URL...
				URL url = new URL(location);
				return new UrlResource(url);
			}
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.
				return getResourceByPath(location);
			}
		}
	}

 

getResource()方法的传入参数,就作为一种策略,要求实现类去判断这种策略的类型,并返回相应的Resource。在这里,Spring是通过try-catch的形式,先判断是否是UrlResource,若不是,则把它当作是ClassPathContextResource来处理。在策略的种类多时,使用if-else判断或switch判断可能更好一点。

 

此外,我们使用策略模式,常常会定义一个策略接口,策略接口有不同的实现类,分别代表不同的策略。如下图:


Spring圆满设计:Resource接口与策略模式
 

在使用策略的时候,将策略接口作为形参,而可传进各种具体的策略实现类对象作为实参,在doSomething()方法中,根据策略的类型,来决定要作出什么样的处理。