user402642
user402642

Reputation:

instanceof versus polymorphism

I am having troubles with the instanceof operator. I'm trying to avoid it. Basically, I have the following structure:

class Shape {}
class Triangle extends Shape {}
class Rectangle extends Shape {}

ShapeParser s;
while (s.hasNext())
     parseShape(s.next()); // returns a Shape object

void parseShape(Triangle t) { // do stuff } // KEY POINT HERE
void parseShape(Rectangle t) { // etc }

The key point I'm making is: I want to do a parameter overload of the function, but it's not working as I intend it to (compile-error). I am trying to avoid:

void parseShape(Shape s)
{
     if (s instanceof Triangle) ...
}

UPDATE: it seems that the consensus is to create a base class method: parseShape() to do the lifting. I wanted to clarify my question: the motivation of this question is relative to the observer pattern. Suppose I have the following Observer object payload method:

    public void update(Observable obj, Shape objectPayload){} 
// note: the objectPayload is usually of type Object

Instead of performing:

public void update(Observable obj, Shape objectPayload)
{
       if (objectPayload instanceof Triangle)
          // do stuff
       else if (objectPayload instanceof Rectangle)
          // etc
}

I want to do:

public void update(Observable obj, Shape objectPayload)
{
       parseShape(objectPayload);
}

    void parseShape(Triangle t) {  } // do stuff
    void parseShape(Rectangle t) { }

Upvotes: 5

Views: 2722

Answers (4)

Ted Hopp
Ted Hopp

Reputation: 234807

You can move the parseShape into each Shape class. Alternatively, you can use the Visitor pattern. There's a neat trick with reflection shown in the solution to this thread that avoids the complexity of a full visitor pattern in Java.

UPDATE:

Here's a recipe for the visitor pattern:

  1. Declare an interface:

    public interface ShapeVisitor {  
        visit(Triangle);  
        visit(Rectangle);  
        // ...  
    }
    
  2. In Shape, declare an abstract method acceptVisitor:

    class Shape {
        public abstract void acceptVisitor(ShapeVisitor visitor);
    }
    
  3. In each concrete class, implement acceptVisitor:

    class Triangle extends Shape {
        public void acceptVisitor(ShapeVisitor visitor) {
            visitor.visit(this);
        }
    }
    
  4. Declare your ParseVisitor class to implement ShapeVisitor and implement all the required methods (simply rename each of the parseShape methods to visit).

The nice things about this are, first, it keeps the parsing code out of your Shape hierarchy and centralizes it in a separate parsing class; second, if you later decide that you need to do some other operation (like, say, render), you can apply the same pattern without ever changing any Shape class. The big down side of this approach is that you will have to change all classes that implement ShapeVisitor if you decide to add another Shape subclass.

Upvotes: 4

Alex Gitelman
Alex Gitelman

Reputation: 24722

I assume that the error is because s.next() returns Shape. Logical thing would be to add parse() method to shape and call s.parse()

Upvotes: 0

If your parseShape() method were declared in Shape, it could be overridden in Triangle and Rectangle.

That is:

ShapeParser s;
while (s.hasNext())
     // Calls the proper implementation of parseShape()
     s.next().parseShape();

Upvotes: 4

Rob
Rob

Reputation: 11733

Um, add a parse method to the base class then just loop and iterate through the list of shapes and call s.parse()?

Upvotes: 1

Related Questions