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

Pages: 1-

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 18:41

I think that using instanceof is more straightforward.

import java.util.LinkedList;

public class SpaceShip
{
  public static abstract class ShipPart
  {
    public int hull = 10;
  }

  public static class ShipEngine extends ShipPart
  {
    public int power = 0;
  }

  public static class ShipWeapon extends ShipPart
  {
    public int damage = 5;
    public int cooldown = 2;
  }

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

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

  public void setEnginesPower(int powerLevel) {
    for(ShipPart pickedPart : parts)
      if(pickedPart instanceof ShipEngine) {
        ((ShipEngine)pickedPart).power = powerLevel;
        System.err.println("POWER LEVEL: " + powerLevel);
      }  
      else
        System.err.println("NOT AN ENGINE!!!");
  }

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

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

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

}

Name: Anonymous 2013-12-02 0:28

**YOU HAVE BEEN VISITED BY LE TOP LEL OF COMEDY GOLD** POST THIS IS 3 threads or lose your sides!
░░░░░░░▄▀▀▀░▄▄▄▄░░░▀▀▀▀▀▀▀▀▄▄░▀
░░░░░░░█░░░░░░░░▀▀▀▀▀▄▄▄▄▄▄▄▄▀░░█
░░░░░▄▀░░░░░░░░░░▄░░░░░░░░▄▄░░░░░▀▄
░░░▄▀░░░░░▄▀▀▀█▄░▀░░░░▄▀▀▀██▀▀▄░░░░░▀
░░▄▀░░▄▄░░▀▀▀▀████▀░░░▀▄▄▀▀▀▀▄█░░░░░░█
░▄▀░▄▀█░░▄▄░░░░░░░█░░░░░▄▄▄░░░▀▀░░░░░░█
▄▀░░█░█░▀░░▀▀▄░░░░░█░░░░░░░▀▀▀▀▀▄░░░░░█
▀▄░░▀░█░░░▄░░░░░░▄▀░░░░▀▄░░░▄▄░░▀▄░█░▄▀
░░▀▄░░░░█▀▄░░░░░▀█░░░░▀▀░█▄▀▄░█░░░█░█
░░░░█░░█░▀▄▀▄▄░░░░▀▀▀░░░▄█▀░▄▀█░░░░▄
░░░░░█░░█░▀▀▄░▀▄▄▄▄▄▄▄▀█░▄█▀▄▀░░░░░
░░░░░█░░▀▄▄░░▀█░░░█░░▄▄▀▀▄▄█▀░░░░▀
░░░░▄▀░░░▀▄▀▀▄░▀▀▀▀▀▀▄▄▀▀▀▄▀░░░░▀
░░░▄▀░░░░░░▀▄░█▄▄▄▄▀▀░▀▄▀▀░░░▄▀▀
░░▄▀░░░░░░░░░▀▄▄▄▄█▄▄▀▀░░░░▄
░░█░░░░░░▀▄▄░░░▄▄▄▄▄▄▀░░░▄▀
░░█░░░░░░░░░▀▀▀▄▄▄▄▄▄▄▀▀
░░░█░░░░░░▀▀▀▀▀░░░░▄
░░░▀▀▄▄▄▄▄▄▄▄▄▀▀▀

Name: Cudder !MhMRSATORI!fR8duoqGZdD/iE5 2013-12-02 2:35

>>3,4
And people wonder why Java programs are so fucking bloated...! :facepalm:

>>2 has solved your problem.

STOP WRITING MORE CODE THAN YOU ABSOLUTELY BLOODY NEED TO!!!

Name: Anonymous 2013-12-02 6:56

that shit is old. use traits now.

Name: Anonymous 2013-12-02 10:36

>>6
Another alternative was proposed on progrider;

Instead of using a list for ship parts, the space ship could have a list for every type of ship parts. This eliminates the need for instanceOf, visitor, or ugly hacks. This probably is preferable when most operation depends on the type of ship part, instead of working with the ship parts as a group.

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

public class SpaceShip
{

    public static class ShipEngine
    {
        public int power = 0;

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

    }

    public static class ShipWeapon
    {
        public int damage = 5;

        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<ShipEngine> engines = new LinkedList<>();
    private final List<ShipWeapon> weapons = new LinkedList<>();

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

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

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

        // two engines and a weapon
        myShip.engines.add(new ShipEngine());
        myShip.engines.add(new ShipEngine());
        myShip.weapons.add(new ShipWeapon());

        myShip.setEnginesPower(100); // power on the engines!
        myShip.setWeaponsDamage(2000); // power the weapons !
    }
}


>>7
I'll check it out

Name: 7 2013-12-02 15:56

>>8
I think they are called "functional interfaces", and are available in Java 8

Name: Cudder !MhMRSATORI!fR8duoqGZdD/iE5 2013-12-03 8:17

>>8
That is one obvious solution but I was assuming OP wanted one of the requirements was to manipulate all the parts as a whole (which also makes sense.)

Name: Anonymous 2013-12-03 23:59

**YOU HAVE BEEN VISITED BY LE TOP LEL OF COMEDY GOLD** POST THIS IS 3 threads or lose your sides!
░░░░░░░▄▀▀▀░▄▄▄▄░░░▀▀▀▀▀▀▀▀▄▄░▀
░░░░░░░█░░░░░░░░▀▀▀▀▀▄▄▄▄▄▄▄▄▀░░█
░░░░░▄▀░░░░░░░░░░▄░░░░░░░░▄▄░░░░░▀▄
░░░▄▀░░░░░▄▀▀▀█▄░▀░░░░▄▀▀▀██▀▀▄░░░░░▀
░░▄▀░░▄▄░░▀▀▀▀████▀░░░▀▄▄▀▀▀▀▄█░░░░░░█
░▄▀░▄▀█░░▄▄░░░░░░░█░░░░░▄▄▄░░░▀▀░░░░░░█
▄▀░░█░█░▀░░▀▀▄░░░░░█░░░░░░░▀▀▀▀▀▄░░░░░█
▀▄░░▀░█░░░▄░░░░░░▄▀░░░░▀▄░░░▄▄░░▀▄░█░▄▀
░░▀▄░░░░█▀▄░░░░░▀█░░░░▀▀░█▄▀▄░█░░░█░█
░░░░█░░█░▀▄▀▄▄░░░░▀▀▀░░░▄█▀░▄▀█░░░░▄
░░░░░█░░█░▀▀▄░▀▄▄▄▄▄▄▄▀█░▄█▀▄▀░░░░░
░░░░░█░░▀▄▄░░▀█░░░█░░▄▄▀▀▄▄█▀░░░░▀
░░░░▄▀░░░▀▄▀▀▄░▀▀▀▀▀▀▄▄▀▀▀▄▀░░░░▀
░░░▄▀░░░░░░▀▄░█▄▄▄▄▀▀░▀▄▀▀░░░▄▀▀
░░▄▀░░░░░░░░░▀▄▄▄▄█▄▄▀▀░░░░▄
░░█░░░░░░▀▄▄░░░▄▄▄▄▄▄▀░░░▄▀
░░█░░░░░░░░░▀▀▀▄▄▄▄▄▄▄▀▀
░░░█░░░░░░▀▀▀▀▀░░░░▄
░░░▀▀▄▄▄▄▄▄▄▄▄▀▀▀

Name: Anonymous 2013-12-04 0:00

**YOU HAVE BEEN VISITED BY LE TOP LEL OF COMEDY GOLD** POST THIS IS 3 threads or lose your sides!
░░░░░░░▄▀▀▀░▄▄▄▄░░░▀▀▀▀▀▀▀▀▄▄░▀
░░░░░░░█░░░░░░░░▀▀▀▀▀▄▄▄▄▄▄▄▄▀░░█
░░░░░▄▀░░░░░░░░░░▄░░░░░░░░▄▄░░░░░▀▄
░░░▄▀░░░░░▄▀▀▀█▄░▀░░░░▄▀▀▀██▀▀▄░░░░░▀
░░▄▀░░▄▄░░▀▀▀▀████▀░░░▀▄▄▀▀▀▀▄█░░░░░░█
░▄▀░▄▀█░░▄▄░░░░░░░█░░░░░▄▄▄░░░▀▀░░░░░░█
▄▀░░█░█░▀░░▀▀▄░░░░░█░░░░░░░▀▀▀▀▀▄░░░░░█
▀▄░░▀░█░░░▄░░░░░░▄▀░░░░▀▄░░░▄▄░░▀▄░█░▄▀
░░▀▄░░░░█▀▄░░░░░▀█░░░░▀▀░█▄▀▄░█░░░█░█
░░░░█░░█░▀▄▀▄▄░░░░▀▀▀░░░▄█▀░▄▀█░░░░▄
░░░░░█░░█░▀▀▄░▀▄▄▄▄▄▄▄▀█░▄█▀▄▀░░░░░
░░░░░█░░▀▄▄░░▀█░░░█░░▄▄▀▀▄▄█▀░░░░▀
░░░░▄▀░░░▀▄▀▀▄░▀▀▀▀▀▀▄▄▀▀▀▄▀░░░░▀
░░░▄▀░░░░░░▀▄░█▄▄▄▄▀▀░▀▄▀▀░░░▄▀▀
░░▄▀░░░░░░░░░▀▄▄▄▄█▄▄▀▀░░░░▄
░░█░░░░░░▀▄▄░░░▄▄▄▄▄▄▀░░░▄▀
░░█░░░░░░░░░▀▀▀▄▄▄▄▄▄▄▀▀
░░░█░░░░░░▀▀▀▀▀░░░░▄
░░░▀▀▄▄▄▄▄▄▄▄▄▀▀▀

Name: Anonymous 2013-12-04 0:39

YOU HAVE BEEN visit()ED BY GANG OF FOUR BLOAT** REFACTOR THIS TO USE 3 threads or lose your job!

Name: Anonymous 2013-12-04 11:30

>>13
ha! good one.

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