james_dean
james_dean

Reputation: 1517

Object Specifc Behaviour in an If Clause

I am working on a game that requires resolution actions depending on the object a ball collides with.

A lot of code within the resolution method applies to all of the different types of objects that could be hit but some is also specific to a particular object type.

The pseudo code looks like this:

resolve (Object a) {

if (some test) {
    if (Object a is rect) {
    // do one thing
    } else {
    // do something else thing
} else if (another test) {
    if (Object a is rect) {
    // do one thing
    } else {
    // do something else thing
} else if (third test) {
    if (Object a is rect) {
    // do one thing
    } else {
    // do something else thing
}
}

However, to a newbie, this feels kind of cluttered (because of the tests for object type within each if clause) but I can't quite figure out how to improve it ? I could override the method and have behavior based on the subclass that is passed to it but then I end up with a lot the same code in both methods.

This method tests the current location of the ball (top, bottom etc) and adjusts the balls velocity accordingly. If object is a rectangle, the new velocity is different to say a circle.

Can anyone offer any assistance?

Upvotes: 1

Views: 88

Answers (2)

Dunes
Dunes

Reputation: 40713

As suggested the visitor pattern is a good idea as it supports modularisation of code. This is because the code for each test is kept its own class and method, thus helping to prevent methods becoming overly long and complex.

It now also means you do not have to check if an Object is a Rectangle or not as this is done by the a technique known as double dispatch. Whereby the GameObject knows what instance of a class it is and therefore calls the appropriate resolve method on the Visitor.

It also helps maintainability as if you need to treat another subclass of GameObject specifically then you first change the ResolveVisitor interface and then start changing the concrete implementations of the visitors. If you forget one by accident then compiler will not let you compile the code and point to the problem.

Here is a verbose example of the visitor pattern:

void resolve(GameObject obj) {
    if (first test) {
        obj.accept(new FirstTestVisitor());
    } else if (second test) {
        obj.accept(new SecondTestVistor());
    } else {
        obj.accept(new DefaultVisitor());
    }
}

interface GameObject {
    public void accept(ResolveVisitor visitor);
}

interface ResolveVisitor {
    public void resolve(Rectangle rect);
    public void resolve(GameObject obj); // default case
}

class Rectangle implements GameObject {
    public void accept(Visitor visitor) {
        visitor.resolve(this);
        // Rectangle and its subclasses will call resolve(Rectangle)
        // whereas all other GameObjects will call resolve(GameObject)
        // though other GameObjects will need their own accept method
    }
}

class FirstTestVisitor implements ResolveVisitor {
    public void accept(Rectangle rect) {
        // logic for first test and if rect goes here
    }
    public void accept(GameObject obj) {
        // logic for first test and not rect goes here
    }
}

Upvotes: 3

codejitsu
codejitsu

Reputation: 3182

You can try to use the visitor pattern: visitor

Or you can do this:resolve(ISomeInterface a) { a.react(ball); } The react-method will be defined in each class of your class hierarchy.

Upvotes: 0

Related Questions