这个模式其实是
Adapter
模式和Decorator
模式的统称。
1. 范例
Servlet规范中的javax.servlet.http.HttpServletRequestWrapper
就是这种模式的经典例子。
-
HttpServletRequestWrapper
继承自ServletRequestWrapper
, 同时实现了HttpServletRequest
。 - 而
ServletRequestWrapper
则是实现了ServletRequest
接口。 - 注意
HttpServletRequestWrapper
和ServletRequestWrapper
都不是abstract, 所以是可以直接拿来用的。 不过我们一般是继承自它,然后覆写我们所关注的方法。
2. 分析
因为这些wrapper可以互相嵌套, 最终造就一个千层饼样式的对象。每一层都是
ServletRequest
类型, 但每层只处理特定的一个需求, 这样就将一个瑞士军刀类里的功能分散了出去。每层饼增强原来瑞士军刀类的一部分功能, 这样就会将原来的瑞士军刀类的功能集拆分为一个个非常小的功能块, 每个功能小块只专注特定的一部分。 如果划分得好的话, 相当于将瑞士军刀类进行了逻辑切割。类的数量增多, 但代码量减小,便于维护和升级。
而且Wrapper模式下,对于同一个方法,各个Wrapper实例的包装顺序和其执行顺序是正好相反的。
3. 代码讲解
// All -- 瑞士军刀类
public class All {
public void a(){
System.out.println("a");
}
public void b(){
System.out.println("b");
}
public void c(){
System.out.println("c");
}
public void X(){
System.out.println("ALL - X");
}
}
// Wrapper模式
public abstract class AllWrapper extends All {
private All under;
protected AllWrapper(All all) {
under = all;
}
@Override
public void a() {
under.a();
}
@Override
public void b() {
under.b();
}
@Override
public void c() {
under.c();
}
@Override
public void X() {
under.X();
}
}
// ----------------- 以下的 A, B, C只关注于某个方法。
// 专注于 a 功能块的处理
public class A extends AllWrapper {
protected A(All all) {
super(all);
}
@Override
public void a() {
System.out.println("A - a");
}
@Override
public void X() {
System.out.println("A - X");
super.X();
}
}
// 专注于 b 功能块的处理
public class B extends AllWrapper {
protected B(All all) {
super(all);
}
@Override
public void b() {
System.out.println("B - b");
}
@Override
public void X() {
System.out.println("B - X");
super.X();
}
}
// 专注于 c 功能块的处理
public class C extends AllWrapper {
protected C(All all) {
super(all);
}
@Override
public void c() {
System.out.println("C - c");
}
@Override
public void X() {
System.out.println("C - X");
super.X();
}
}
// 单元测试
public class DesignPattern_Wrapper_Tests {
@Test
public void testname() throws Exception {
All all = new All();
// a
// b
// c
all.a();
all.b();
all.c();
all = new A(all);
all = new B(all);
all = new C(all);
// A - a
// B - b
// C - c
// 可以尝试注释掉上面的某一行代码, 查看输出结果
all.a();
all.b();
all.c();
// ----- 和上面的注入顺序正好相反
// C - X
// B - X
// A - X
// ALL - X
all.X();
}
}
4. 总结
这种文章本来应该是入行一两年的时候就写下的。之所以推迟到了现在,一言难尽啦!