Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Visitor vs. instanceof

Name: Anonymous 2013-12-01 16:19

Hello /prog/,
I'd like to know what do you think of this. When you must add an operation that only affects some elements of a list based on their type, would you use a visitor, or instanceof?

Here's an example where I want to power all the engines of a space ship. Would you make different lists for every type of parts, use instanceof ShipEngine, or use a visitor?

import java.util.LinkedList;
import java.util.List;

public class SpaceShip
{

    // The ship parts
   
    public static interface ShipPart
    {
        void accept(ShipPartVisitor visitor);
    }

    public static class ShipEngine implements ShipPart
    {
        public int power = 0;

        @Override
        public void accept(ShipPartVisitor visitor)
        {
            visitor.visit(this);
        }

    }

    public static class ShipWeapon implements ShipPart
    {
        public int damage = 5, cooldown = 2;

        @Override
        public void accept(ShipPartVisitor visitor)
        {
            visitor.visit(this);
        }
    }
   
    // The interface for visitors

    public static interface ShipPartVisitor
    {
        void visit(ShipEngine shipEngine);

        void visit(ShipWeapon shipWeapon);
    }

    // The methods and fields of the SpaceShip class
   
    private final List<ShipPart> parts = new LinkedList<>();
   
    public void addPart(ShipPart part)
    {
        parts.add(part);
    }

    public void setEnginesPower(final int powerLevel)
    {
        ShipPartVisitor visitor = new ShipPartVisitor()
        {

            @Override
            public void visit(ShipWeapon shipWeapon)
            {
                // we're not playing with the weapons
            }

            @Override
            public void visit(ShipEngine shipEngine)
            {
                shipEngine.power = powerLevel;
                System.err.println("POWER LEVEL : " + powerLevel);
            }
        };

        for (ShipPart pickedPart : parts)
            pickedPart.accept(visitor);
    }

    public static void main(String[] args)
    {
        SpaceShip myShip = new SpaceShip();
       
        // two engines and a weapon
       
        myShip.addPart(new ShipEngine());
        myShip.addPart(new ShipEngine());
        myShip.addPart(new ShipWeapon());
       
        // power on the engines!
       
        myShip.setEnginesPower(100);
    }

}

Name: Anonymous 2013-12-01 20:09

>>2
yeah, it is more concise, but I try to avoid casting/instanceof... especially when I'm not doing maintenance, but construction of a program.
Maybe there is a way to forward the "set engine power" message to the parts, and let them choose if they do something or not, instead of using a visitor or testing the type directly.
Of course, we could add setEnginePower to the ShipPart interface, but then we'd bloat all the other ship parts with no-op for this operation. But then, we could make the parts extend an abstract class which implements ShipPart (which has all the methods of all the parts) and fill it with no-op for every operation. Then, the parts would only override the revelant methods.

This is a lot of work for a simple problem though...

Name: Anonymous 2013-12-01 20:17

>>3
Here's what I meant. It feels like a hack, but it works!
import java.util.LinkedList;
import java.util.List;

public class SpaceShip
{

    // this is a hack...
    public static interface ShipPart
    {
        void setEnginePower(int powerLevel);

        void setWeaponDamage(int damage);
    }

    /*
     * No-op for every methods, it is left to the concrete parts to implement the methods they want.
     */
    public static class DefaultShipPart implements ShipPart
    {

        @Override
        public void setEnginePower(int powerLevel)
        {
            // no-op is default
        }

        @Override
        public void setWeaponDamage(int damage)
        {
            // no-op is default
        }

    }

    public static class ShipEngine extends DefaultShipPart
    {
        public int power = 0;

        @Override
        public void setEnginePower(int newPower)
        {
            System.err.println("ENGINE POWER MODIFIED : " + power + " TO " + newPower);
            power = newPower;
        }

    }

    public static class ShipWeapon extends DefaultShipPart
    {
        public int damage = 5, cooldown = 2;

        @Override
        public void setWeaponDamage(int newDamage)
        {
            System.err.println("WEAPON DAMAGE MODIFIED : " + damage + " TO " + newDamage);
            damage = newDamage;
        }

    }

    // The methods and fields of the SpaceShip class

    private final List<ShipPart> parts = new LinkedList<>();

    public void addPart(ShipPart part)
    {
        parts.add(part);
    }

    public void setEnginesPower(final int powerLevel)
    {
        for (ShipPart pickedPart : parts)
            pickedPart.setEnginePower(powerLevel);
    }

    public void setWeaponsDamage(final int damage)
    {
        for (ShipPart pickedPart : parts)
            pickedPart.setWeaponDamage(damage);
    }

    public static void main(String[] args)
    {
        SpaceShip myShip = new SpaceShip();

        // two engines and a weapon

        myShip.addPart(new ShipEngine());
        myShip.addPart(new ShipEngine());
        myShip.addPart(new ShipWeapon());

        // power on the engines!

        myShip.setEnginesPower(100);

        // power the weapons !

        myShip.setWeaponsDamage(2000);
    }

}

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List