AndideBob
AndideBob

Reputation: 160

Java - Behavioral decisions "instanceof" vs flag

I am currently working on a piece of code, in which behavioral decisions are made based on whether the request object is of a certain sub-type, like so:

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 in this case has nothing else implemented, that would distinguish it from a normal Request. My question now is, if there are any advantages or disadvantages from using this style instead:

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

I understand how the second Method could get very convoluted the more decisions I want to make. But I am also interested in how these two approaches compare performance wise.

Thanks in advance.

EDIT: First of all thanks for the quick response. I should have probably mentioned, that my Request and my SpecialRequest are supposed to merely carrying data, and not contain any logic. That's just how the whole software is designed. My method just consumed the request and is supposed to behave differently based on whether the request is special or not. "instanceof" just seems like dirty code to me, but the boolean also doesn't seem quite right. Any advice is still welcome.

Upvotes: 0

Views: 308

Answers (3)

Jonas
Jonas

Reputation: 524

You might also consider using the visitor pattern (https://en.wikipedia.org/wiki/Visitor_pattern), as it ensures type-safety and does not need the instanceof-check. Furthermore it is more obvious where you have to extend/ modify your code, when you create a new type of request (e.g. "VerySpecialRequest").

All you have to do is to create an interface with visit-methods for every type you want to execute special code, like this:

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

The request classes need accept-methods that do nothing but calling the visitor with itself:

public class Request {

  ...

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

Same for SpecialRequest:

public class SpecialRequest extends Request {

  ...

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

Then you can simply implement your logic in a class that implements the interface (here as an anonymous 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);

As you can see there are no more instance-of checks. Another advantage of this is that you can "process requests" even if they are no direct subclass of 'Request' - all you have to do is to extract the accept-method in its own interface. Hope this helps.

Upvotes: 1

David Arellano
David Arellano

Reputation: 32

1.- insteadof, is a type comparison operator because it compares the instance with type. It returns either true or false. If you apply the instanceof operator with any variable that has null value, it returns false.

2.- isSpecial(), is a method of your own. You can do what ever you want in that piece of code, so the comparisson in that case is up to you.

3.- You have to be aware that when you use instanceof, the comparison also do a class cast of the variable in mention, so if that can't be done, you should get a compile time error. see this : compile time error with instanceof

4.- if you use this operator to much, you should check it, because that's a signal of some bad code. For more details see this: use of instaceof

Upvotes: 0

Michael
Michael

Reputation: 44150

The clear advantage of using a method is that it's not closely tied to a particular type. You could add a new class VerySpecialRequest which also provides this behaviour, and you wouldn't necessarily need to extend SpecialRequest in order to do that.


However, the more pressing issue here is that you have explicit conditional branching at all. The object should be responsible for determining whether there's any additional behaviour required, and then the nasty conditional logic goes away altogether:

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...");
    }
}

Upvotes: 4

Related Questions