装饰图案
我不经常使用的一种设计模式是Decorator 。 我不确定为什么这种模式不受欢迎,因为它很方便。 装饰器模式允许以受控方式向对象添加功能。 即使在使用静态类型的语言时,也可以在运行时运行! 装饰器模式是子类的替代方法。 子类化在编译时增加了行为,并且更改会影响原始类的所有实例; 装饰可以在运行时为单个对象提供新的行为。 装饰器模式是遵守打开/关闭原则的好工具。
一些示例可能显示此模式的价值:
示例1:HTTP身份验证
想象一下一个HTTP客户端,例如与RESTful服务对话的客户端。
该服务的某些部分可公开访问,但某些部分需要用户登录。当客户端尝试访问受保护的资源时,RESTful服务将以401 Unauthorized
状态码响应。
更改客户端以处理401会导致重复,因为每个调用都可能需要身份验证 。 因此,我们应该将身份验证代码提取到一个位置。 但是那个地方在哪里?
这是Decorator模式出现的地方:
public class AuthenticatingHttpClientimplements HttpClient {private final HttpClient wrapped;public AuthenticatingHttpClient(HttpClient wrapped) {this.wrapped = wrapped;}@Overridepublic Response execute(Request request) {Response response = wrapped.execute(request);if (response.getStatusCode() == 401) {authenticate();response = wrapped.execute(request);}return response;}protected void authenticate() {// ...}}
REST客户端现在不再需要担心身份验证,因为AuthenticatingHttpClient
处理AuthenticatingHttpClient
。
示例2:缓存授权决策
OK,因此用户已登录,REST服务器知道她的身份。 它可能决定允许一个人访问某个资源,而不允许另一个人访问。
IOW,它可以使用XACML来实现授权 。 在这种情况下, 策略决策点 (PDP)负责决定访问请求。
检查权限通常很昂贵,尤其是当权限变得更细粒度并且访问策略更加复杂时。 由于访问策略通常不会经常更改,因此这是缓存的理想选择。
这是装饰器模式可能派上用场的另一个实例:
public class CachingPdp implements Pdp {private final Pdp wrapped;public CachingPdp(Pdp wrapped) {this.wrapped = wrapped;}@Overridepublic ResponseContext decide(RequestContext request) {ResponseContext response = getCached(request);if (response == null) {response = wrapped.decide(request);cache(request, response);}return response;}protected ResponseContext getCached(RequestContext request) {// ...}protected void cache(RequestContext request, ResponseContext response) {// ...}}
如您所见,代码与第一个示例非常相似,这就是为什么我们将其称为模式。
正如您可能从这两个示例中猜到的那样,Decorator模式对于实现跨领域的关注点非常有用,例如身份验证,授权和审核的安全功能,但这当然不是唯一的亮点。
如果您仔细看,我相信您将能够发现更多使这种模式起作用的机会。
翻译自: https://www.javacodegeeks.com/2014/01/the-decorator-pattern.html