Java - 行为决策" instanceof" vs flag

时间:2018-05-02 10:49:30

标签: java performance oop instanceof

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

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没有其他任何实现,这将区别于普通请求。我现在的问题是,如果使用这种风格有任何优点或缺点:

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"对我来说似乎只是脏代码,但布尔值似乎并不合适。任何建议仍然受欢迎。

3 个答案:

答案 0 :(得分:4)

使用方法的明显优势在于它与特定类型没有紧密联系。您可以添加一个新类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 :(得分:1)

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

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

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

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

public class Request {

  ...

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

同样的SpecialRequest:

public class SpecialRequest extends Request {

  ...

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

然后你可以简单地在实现接口的类中实现你的逻辑(这里是一个匿名类):

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);

正如您所看到的,没有更多的检查实例。这样做的另一个好处是,即使它们不是“请求”的直接子类,您也可以“处理请求” - 您所要做的就是在自己的接口中提取accept方法。希望这会有所帮助。

答案 2 :(得分:0)

1.-而不是,是一个类型比较运算符,因为它将实例与类型进行比较。它返回true或false。如果将instanceof运算符应用于具有null值的任何变量,则返回false。

2.- isSpecial(),是您自己的方法。你可以在那段代码中做你想做的事情,所以那个案例中的比较由你决定。

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

4.-如果你多使用这个操作符,你应该检查它,因为这是一些不良代码的信号。有关详细信息,请参阅:use of instaceof