文档章节

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

FansUnion
 FansUnion
发布于 2015/05/03 01:30
字数 1393
阅读 6
收藏 0
装饰模式(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);
 }
}
 --------------------------------------------------------------------------------------------------------------------------------------------
程序运行结果

 

图片

© 著作权归作者所有

FansUnion
粉丝 60
博文 858
码字总数 825464
作品 0
丰台
高级程序员
私信 提问
PHP设计模式(二):结构模式

上一篇我们介绍了设计模式的特性并且详细讲解了4种创建型模式,创建型模式是负责如何产生对象实例的,现在我们继续来给大家介绍结构型模式。(我的分享里面有) 一、什么是结构型模式? 结构...

juhenj
2014/05/15
675
1
设计模式梳理(一)

设计模式梳理(一) 总体来说设计模式分为三大类: @案例源码地址:https://gitlab.com/lxqxsyu/DisgnPattern 创建型模式 简单工厂模式 工厂类是整个模式的关键。它包含必要的判断逻辑,能够...

lxq_xsyu
2017/11/02
0
0
小菜学设计模式——设计模式总结之结构型

1、设计模式总结 设计模式总共23个,但是常用的不到10个,下面就把这23个设计模式进行整理归类,具体如下: 1)创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型...

learn_more
2015/07/06
0
0
JavaScript常用设计模式

设计模式 设计模式是一种在长时间的经验与错误中总结出来可服用的解决方案。 设计模式主要分为3类: 创建型设计模式:专注于处理对象的创建 Constructor构造器模式,Factory工厂模式,Singl...

a独家记忆
2018/07/13
0
0
PHP设计模式(一):简介及创建型模式

我们分三篇文章来总结一下设计模式在PHP中的应用,这是第一篇创建型模式。 一、设计模式简介 首先我们来认识一下什么是设计模式: 设计模式是一套被反复使用、容易被他人理解的、可靠的代码设...

juhenj
2014/05/15
228
2

没有更多内容

加载失败,请刷新页面

加载更多

C 语言 二级指针的使用

#include <stdio.h>#include <stdlib.h>typedef struct node Node;struct node {int data;struct node* next;struct node* prev;};Node head;Node* insert(Node......

小张525
25分钟前
2
0
【大数据技术】——Hadoop(1)

什么是大数据 基本概念 《数据处理》 在互联网技术发展到现今阶段,大量日常、工作等事务产生的数据都已经信息化,人类产生的数据量相比以前有了爆炸式的增长,以前的传统的数据处理技术已经...

须臾之余
39分钟前
6
0
比特币从地址逆向计算私钥

区块链 区块链简介 说到比特币,就不得不提区块链。那什么是区块链呢? 区块链本质是一个数据集,只不过数据的组织采用了比较特殊的方式,就是把数据拆分为一块一块的小数据集。 为什么要进行...

trayvon
53分钟前
1
0
TypeScript……真香

写前端或者用 node 写命令行小工具一直采用的 es6 的语法,对于 TypeScript 则是秉持敬而远之的态度,毕竟团队中多推广一门语言所需要花费的精力都是让人望而却步的。所以对于 JavaScript 的...

郁也风
59分钟前
3
0
shell基本案例

1、自定义rm linux系统的rm命令太危险,一不小心就会删除掉系统文件。 写一个shell脚本来替换系统的rm命令,要求当删除一个文件或者目录时,都要做一个备份,然后再删除。下面分两种情况,做...

寰宇01
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部