`
FansUnion
  • 浏览: 153179 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

 
阅读更多
装饰模式(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);
}
}
--------------------------------------------------------------------------------------------------------------------------------------------
程序运行结果

图片

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics