设计模式之包装器/wapper/装饰模式的应用

简介

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
在很多博文里会引入Decorator角色,觉得把简单问题复杂化了。等下看一下Request的应用就知道实际用起来比类图简单的多。

源码中的应用

以RequestWrapper为例,这是一个十分有代表性的类。在debug的时候经常会发现,request套了一个又一个,因为他们一直在互相wrapper。点到最后才看到request的参数。每一层包装其实都是一次加强。
在这里插入图片描述
他的实际代码结构就是一个Request的子类,并在类里声明了一个对象存储Request,继承Request的接口都由这个对象来实际去执行。然后自己再去做增强的工作。
代码如下:

public class HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest {

    public HttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    private HttpServletRequest _getHttpServletRequest() {
        return (HttpServletRequest) super.getRequest();
    }

    @Override
    public String getAuthType() {
        return this._getHttpServletRequest().getAuthType();
    }

    @Override
    public Cookie[] getCookies() {
        return this._getHttpServletRequest().getCookies();
    }

    @Override
    public long getDateHeader(String name) {
        return this._getHttpServletRequest().getDateHeader(name);
    }

    @Override
    public String getHeader(String name) {
        return this._getHttpServletRequest().getHeader(name);
    }

    @Override
    public Enumeration<String> getHeaders(String name) {
        return this._getHttpServletRequest().getHeaders(name);
    }
    // 后续代码类似,都是执行_getHttpServletRequest的方法,省略了。
}

开发中的应用

一般场景是用不到的,刚好碰到了并且想到了这个模式,一拍即合。
需求如下:
要整合Spring security框架,里面有个类叫UserDetails,是security中存储用户的地方,但是这个对象没有部门、公司等信息,在实际应用中数据不够。但是security所有的组件交互的对象都是他,所以又必须实现这个接口。
看到的一个代码他的实现方式是:写一个类继承UserDetails,然后在写deptId,companyId等属性。在交互的时候调一次构造函数,把这些参数在一个一个传进去(除了deptId,companyId以外,userDetails的参数也要拼进去),代码不美观。

public UserDetails loadUserByUsername(String username){
	// 前面代码省略了,就看返回的一段
	return new MyUser(user.getUserId(), user.getDeptId(), user.getPhone(),
				user.getUsername(),  user.getPassword(), enabled, true, true,
				true, authorities);
}

如果用wrapper代码传递上就很简单:

public UserDetails loadUserByUsername(String username){
	// 前面代码省略了,就看返回的一段
	return new UserDetailsWrapper(user.getUserId(), user.getDeptId(), user.getPhone(),
				userdetails);
}

另外,如果出现UserDetails在系统中需要多个维度叠加功能(基本不会出现)的话,这个模式也很好用。
类似的ClientDetails类,我们用数据库存储这个信息的话,他的类本身有很多属性是set或者map的,而且权限信息是需要从权限表去读,这些都无法直接从库里单表转化,所以需要有一个entity类与db做映射,然后用一个BO类二次封装。
即定义一个如下类

public class ClientDetailsBO implements ClientDetails{
	private ClientDetailsEntity delegate;
	private Set<GrantedAuthority> authorities;
	@Override
    public String getClientId() {
        return delegate.getClientId();
    }

    @Override
    public Set<String> getResourceIds() {
    	// 数据库里这个resourceId是存的逗号隔开的资源列表,是string方式,所以这个接口里要做个转化
        return stringToSet(delegate.getResourceIds());
    }

    @Override
    public boolean isSecretRequired() {
        return delegate.isSecretRequired();
    }
}

这样的话从entity转换成security自带的clientDetails就比较方便。不用一个一个读取再一个一个set。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值