设计模式实战6--结构型--装饰模式

来源:互联网 发布:沃伦夫妇纪录片 知乎 编辑:程序博客网 时间:2024/06/05 14:24
装饰模式(Decorator)定义:动态地给一个对象添加一些额外的职责。就扩展功能而言, 它比生成子类方式更为灵活。
装饰模式结构图:

 

图片

 

装饰模式解析:
     Component:
组件对象的接口,可以给这些对象动态的添加职责。
    ConcreteComponent:
具体的组件对象,实现组件对象接口,通常就是被装饰器装饰的原始对象,也就是可以给这个对象添加职责。
    Decorator:
所有装饰器的抽象父类,需要定义一个与组件接口一致的接口,并持有一个Component对象,其实就是持有一个被装饰的对象。
注意这个被装饰的对象不一定是最原始的那个对象了,也可能是被其它装饰器装饰过后的对象,反正都是实现的同一个接口,也就是同一类型。
    ConcreteDecorator:
实际的装饰器对象,实现具体要向被装饰对象添加的功能。
 
 
装饰模式实战:

 包的结构图如下:

图片

 

      源码如下:
-------------------------------模仿Servlet规范,定义接口----------------------------------------
package org.leiwen.dp.structure.decorator.request;
public interface Filter {
 // public abstract void init(javax.servlet.FilterConfig fiterConfig);
 // 简化处理
 public abstract void init();
 void doFilter(HttpServletRequest req, HttpServletResponse res,FilterChain chain);
 public abstract void destroy();
}
 
package org.leiwen.dp.structure.decorator.request;
//过滤器链
public interface FilterChain {
 void doFilter(HttpServletRequest req, HttpServletResponse res);
}
package org.leiwen.dp.structure.decorator.request;
public interface HttpServletRequest {
 public Object getAttribute(String name);
 public void setAttribute(String name, Object value);
}
 
package org.leiwen.dp.structure.decorator.request;
public interface HttpServletResponse {
 // 什么也没有,只是演示而已.我是打酱油的。
}
 
--------------------------------接口的实现类--------------------------------------------------------------------
package org.leiwen.dp.structure.decorator.request.impl;
import org.leiwen.dp.structure.decorator.request.HttpServletResponse;
public class HttpServletResponseImpl implements HttpServletResponse {
 // 什么也没有,只是演示而已.我是打酱油的。
}
package org.leiwen.dp.structure.decorator.request.impl;
import org.leiwen.dp.structure.decorator.request.FilterChain;
import org.leiwen.dp.structure.decorator.request.HttpServletRequest;
import org.leiwen.dp.structure.decorator.request.HttpServletResponse;
public class FilterChainImpl implements FilterChain {
  @Override
 public void doFilter(HttpServletRequest req, HttpServletResponse res) {
   // 什么也没有,只是演示而已.我是打酱油的。
 }
}
package org.leiwen.dp.structure.decorator.request.impl;
import java.util.HashMap;
import java.util.Map;
import org.leiwen.dp.structure.decorator.request.HttpServletRequest;
 
public class HttpServletRequestImpl implements HttpServletRequest {
 private Map<String, Object> context = new HashMap<String, Object>();
 @Override
 public Object getAttribute(String name) {
  return context.get(name);
 }
 @Override
 public void setAttribute(String name, Object value) {
  context.put(name, value);
 }
}
 
package org.leiwen.dp.structure.decorator.request.impl;
import org.leiwen.dp.structure.decorator.request.Filter;
import org.leiwen.dp.structure.decorator.request.FilterChain;
import org.leiwen.dp.structure.decorator.request.HttpServletRequest;
import org.leiwen.dp.structure.decorator.request.HttpServletResponse;
import org.leiwen.dp.structure.decorator.request.decorator.CacheManager;
import org.leiwen.dp.structure.decorator.request.decorator.HttpServletRequestWrapper;
/**
 * 最初,我误解了Struts2技术内幕上的这个例子。
 *
 * 书中的例子,即本代码,想要表明的是:变量如果以CACHE_PREFIX为前缀,就从缓存中读取数据, 否则就从request中读取数据。
 *
 * 即request只是增加了了“从缓存中读取数据”的新特性。
 *
 * 误解--注意:在缓存存在的情况下,我们通常优先从缓存中读取数据,缓存中没有的话再从其它地方读取数据。然而,这不是本例实现的功能。
 * 如果需要实现这个功能,有几个地方需要变更,但是仍然可以使用装饰模式实现。
 */

public class DecoratorSampleFilter implements Filter {
 public void doFilter(HttpServletRequest req, HttpServletResponse res,
   FilterChain chain) {
  // 对request进行装饰,增加功能
  HttpServletRequest request = new HttpServletRequestWrapper(req);
  // 从缓存中获取数据
  Object cachefans = request.getAttribute(CacheManager.CACHE_PREFIX
    + "fans");
  Object decorator = request.getAttribute(CacheManager.CACHE_PREFIX
    + "decorator");
  Object softfans = request.getAttribute(CacheManager.CACHE_PREFIX
    + "softfans");
  // 从reqest中的获取数据
  Object fans = request.getAttribute("fans");
  Object leiwen = request.getAttribute("leiwen");
  //打印数据
  println("以下是从缓存中获取到的数据:");
  println("cache fans=" + cachefans);
  println("decorator=" + decorator);
  println("softfans=" + softfans);
  println("");
  println("以下是直接从request中获取到的数据:");
  println("fans=" + fans);
  println("leiwen=" + leiwen);
  chain.doFilter(req, res);
 }
 @Override
 public void init() {
  // 什么也没有,只是演示而已.
 }
 @Override
 public void destroy() {
  // 什么也没有,只是演示而已.
 }
 // 简单的工具方法,打印对象
 public static void println(Object content) {
  System.out.println(content);
 }
}
 
 
-----------------------------------------装饰类--增加的功能-------------------------------------------------------
 
package org.leiwen.dp.structure.decorator.request.decorator;
import java.util.HashMap;
import java.util.Map;
/**
 * 缓存管理器,这个类只是简单地抽象了缓存管理的部分方法,缓存管理的具体完整实现可以自行实现。
 */
public class CacheManager {
 private Map<String, Object> caches = new HashMap<String, Object>();
 public static final String CACHE_PREFIX = "cache.";
 // 故意向缓存中增加一些数据,实际应用中可以采取其它方式
 {
  caches.put("fans", "I am a fans of cache!");
  caches.put("decorator", "Decorator Pattern");
  caches.put("softfans", "软林至尊,Fans同盟。号令天下,莫敢不从。");
 }
 // 向缓存中存储对象
 public void setValue(String name, Object obj) {
  caches.put(name, obj);
 }
 // 从缓存中获取对象
 public Object getValue(String name) {
  return caches.get(name);
 }
}
 
package org.leiwen.dp.structure.decorator.request.decorator;
import org.leiwen.dp.structure.decorator.request.HttpServletRequest;
 
public class HttpServletRequestWrapper implements HttpServletRequest {
 private CacheManager cacheManager = new CacheManager();
 // 封装了目标接口,而不是具体实现
 private HttpServletRequest request;
 // HttpServletRequest是一个接口而不是一个具体的实现类,解耦合。
 public HttpServletRequestWrapper(HttpServletRequest request) {
  this.request = request;
 }
 @Override
 public Object getAttribute(String name) {
  // 这样一来,我们就在整个request生命周期获得了HttpServletRequest的扩展:
  // 因为对于HttpServletRequest来说,其原生的getAttribute方法的行为被加入了
  // “从缓存中读取数据”的新特性。从扩展的灵活度来看,这种实现方法也做到了“从默认目标实现进行选择性扩展”:
  // 我们发现可以在这个类的实现中,只有满足以CACHE_PREFIX开始的属性表达式才会被扩展,否将还将调用原始
  
// 的HttpServletRequest完成逻辑。
  // 首先在缓冲中查找,再调用父类方法进行查找
  if (name != null && name.startsWith(CacheManager.CACHE_PREFIX)) {
   String cacheKey = name
     .substring(CacheManager.CACHE_PREFIX.length());
   return cacheManager.getValue(cacheKey);
  } else {
   return request.getAttribute(name);
  }
 }
 @Override
 public void setAttribute(String name, Object value) {
  request.setAttribute(name, value);
 }
}
-----------------------------------------测试装饰模式-------------------------------------------------------
package org.leiwen.dp.structure.decorator.request.test;
import org.leiwen.dp.structure.decorator.request.Filter;
import org.leiwen.dp.structure.decorator.request.FilterChain;
import org.leiwen.dp.structure.decorator.request.HttpServletRequest;
import org.leiwen.dp.structure.decorator.request.HttpServletResponse;
import org.leiwen.dp.structure.decorator.request.impl.DecoratorSampleFilter;
import org.leiwen.dp.structure.decorator.request.impl.FilterChainImpl;
import org.leiwen.dp.structure.decorator.request.impl.HttpServletRequestImpl;
/**
 * @author 雷文 2012-3-24
 */
public class DecoratorTest {
 // 我们可以把这个main函数想象成Tomcat等Web容器
 public static void main(String[] args) {
  // “遵循Servlet规范”,构造对象,准备Web环境
  HttpServletRequest req = new HttpServletRequestImpl();
  req.setAttribute("fans", "I am fans.");
  req.setAttribute("leiwen", "Hello,everyone.I am leiwen.");
  // 本例的重点不在于此,而在于request。FilterChain和HttpServletResponse完全可以为null。
  HttpServletResponse res = null;
  FilterChain chain = new FilterChainImpl();
  
  //"Tomcat容器"调用我们自己实现的Filter
  Filter filter = new DecoratorSampleFilter();
  filter.doFilter(req, res, chain);
 }
}
 --------------------------------------------------------------------------------------------------------------------------------------------
程序运行结果

 

图片

原创粉丝点击