如何扩展防御性编码实现?例如。 vert.x CorsHandlerImpl

时间:2016-12-09 10:10:03

标签: java vert.x

有像vert.x这样的防御性编码库。使用带有静态工厂方式的接口来返回实现。开发人员可以使用他们的实现,但是当它不是完全所需的时候 - 它是不可能扩展它的。不幸的是,它甚至将实现绑定到接口。为什么?

扩展此类的推荐方法是什么?除了复制整个班级以外,还必须有其他方法,只需重写几行所需的行......

例如:io.vertx.ext.web.handler.CorsHandler的vert.x实现

public interface CorsHandler {
  static CorsHandler create(String allowedOriginPattern) {
    return new CorsHandlerImpl(allowedOriginPattern);
  }
  ...
}


public class CorsHandlerImpl implements CorsHandler {
  private boolean isValidOrigin(String origin) {
  }
  ...
}


public class MyCorsHandler implement/extends CorsHandler/impl {
  @Override
  protected boolean isValidOrigin(String origin) {
    // my changes 
  }
}

2 个答案:

答案 0 :(得分:1)

可以包装类而不是扩展它,只更改需要不同实现的方法。

此解决方案称为Adapter Pattern

  

在软件工程中,适配器模式是一种软件设计模式(也称为Wrapper,与Decorator模式共享的替代命名),它允许将现有类的接口用作另一个接口。1 它经常用于使现有的类与其他类一起使用而无需修改其源代码

考虑扩展其他人编写的现有类通常不是一个好主意。事实上,在下面的版本中,它们的内部实现可以改变,并且这些更改可以反映在扩展类上,以某种方式无法预测的方式改变它们的行为。

这是一个显示:

的例子

想象一下,您需要使用自定义实现扩展ArrayList以记录所有添加的项目。

实际上你可以重写add和addAll方法,如下所示:

public void add(E e) {
   System.out.println("add item " + e);
   super.add(e);
}

public void addAll(Collection<? extends E> c) {
   for (E e : c) {
       System.out.println("add item " + e);
   }
   super.addAll(c);
}

这是有效的,因为addAll的内部实施不会调用add。但是,如果addAll的实现因集合c上的循环而更改,则会为您的代码无效的每个元素调用add。因此,更改基类将改变派生类的行为。

答案 1 :(得分:0)

对于CorsHandler,我会继续扩展Impl并覆盖处理方法:

class MyCorsHandler extends CorsHandlerImpl {

    public MyCorsHandler(String allowedOriginPattern) {
        super(allowedOriginPattern);
    }

    @Override
    public void handle(RoutingContext context) {
        HttpServerRequest request = context.request();
        HttpServerResponse response = context.response();
        String origin = context.request().headers().get(ORIGIN);
        if (origin == null) {
            // Not a CORS request - we don't set any headers and just call the next handler
            context.next();
        } else if (isMyValidOrigin(origin)) {
            context.next();
        } else {
            super.handle(context);
        }
    }

    private boolean isMyValidOrigin(String origin) {
        // Do something there
        return false;
    }
}