Java - 行为决策 "instanceof" vs flag

Java - Behavioral decisions "instanceof" vs flag

我目前正在编写一段代码,其中根据请求对象是否属于某个子类型来做出行为决策,如下所示:

class Request{
    public void doThing(){
        System.out.println("doing Thing...");
    }
}

class SpecialRequest extends Request{
    ...
}

void method(Request request){
    if(request instanceof SpecialRequest){
        System.out.println("is special...");
    }
    request.doThing();
}

在这种情况下,SpecialRequest 没有实现其他任何东西,这将把它与普通的 Request 区分开来。我现在的问题是,使用这种风格是否有任何优点或缺点:

class Request{
    ...

    public boolean isSpecial(){
        return special;
    }

    public void doThing(){
        System.out.println("doing Thing...");
    }
}

void method(Request request){
    if(request.isSpecial()){
        System.out.println("is special...");
    }
    request.doThing();
}

我理解第二种方法如何变得非常复杂,因为我想做的决定越多。但我也对这两种方法如何比较性能感兴趣。

提前致谢。

编辑:首先感谢您的快速回复。我可能应该提到,我的 Request 和 SpecialRequest 应该只是携带数据,而不包含任何逻辑。这就是整个软件的设计方式。我的方法只是消耗了请求,并且应该根据请求是否特殊而有不同的行为。 "instanceof" 对我来说似乎是脏代码,但布尔值似乎也不太正确。仍然欢迎任何建议。

使用方法的明显优势在于它不与特定类型紧密相关。您可以添加一个新的 class VerySpecialRequest,它也提供此行为,并且您不一定需要扩展 SpecialRequest 才能做到这一点。


然而,这里更紧迫的问题是你有明确的条件分支。该对象应该负责确定是否需要任何额外的行为,然后讨厌的条件逻辑就完全消失了:

class Request{
    public void doThing(){
        System.out.println("doing Thing...");
    }
}

class SpecialRequest extends Request{
    @Override
    public void doThing(){
        super.doThing();
        System.out.println("is special...");
    }
}

1.- 而不是,是类型比较运算符,因为它将实例与类型进行比较。它 returns 非真即假。如果将 instanceof 运算符应用于任何具有空值的变量,它 returns false.

2.- isSpecial(),是你自己的一个方法。你可以在那段代码中做任何你想做的事情,所以这种情况下的比较取决于你。

3.- 你必须知道,当你使用 instanceof 时,比较也会对提到的变量进行 class 转换,所以如果不能这样做,你应该进行编译时间错误。看到这个:compile time error with instanceof

4.- 如果你经常使用这个运算符,你应该检查它,因为这是一些错误代码的信号。有关详细信息,请参阅:use of instaceof

您也可以考虑使用访问者模式 (https://en.wikipedia.org/wiki/Visitor_pattern),因为它确保类型安全并且不需要 instanceof-check。此外,当您创建新类型的请求(例如 "VerySpecialRequest")时,您必须在何处扩展/修改代码更为明显(例如 "VerySpecialRequest")。

您所要做的就是为您要执行特殊代码的每种类型创建一个带有访问方法的接口,如下所示:

public interface RequestProcessor {
  void visit(Request request);
  void visit(SpecialRequest specialRequest);
}

请求 classes 需要 accept-methods,除了用它自己调用访问者之外什么都不做:

public class Request {

  ...

  void accept(RequestProcessor requestProcessor) {
    requestProcessor.visit(this);
  }
}

特殊请求相同:

public class SpecialRequest extends Request {

  ...

  @Override
  void accept(RequestProcessor requestProcessor) {
    requestProcessor.visit(this);
  }
}

然后您可以简单地在实现接口的 class 中实现您的逻辑(此处为匿名 class):

RequestProcessor requestProcessor = new RequestProcessor() {

  @Override
  public void visit(Request request) {
    System.out.println("I'm a normal request");
  }

  @Override
  public void visit(SpecialRequest specialRequest) {
    System.out.println("I'm a special request");
  }
};


Request request = new Request();
request.accept(requestProcessor);

SpecialRequest specialRequest = new SpecialRequest();
specialRequest.accept(requestProcessor);

如您所见,没有更多实例检查。这样做的另一个优点是,即使它们不是 'Request' 的直接子 class,您也可以 "process requests" - 您所要做的就是在其自己的界面中提取接受方法。希望这有帮助。