2

I searched about this subjet arround here in Stack Overflow. I found the following solution:

Explanation of Visitor Pattern

Now, my case is simillar to this one. I need, however, to avoid the use of "instanceOf".

I have a game that has towers named MonkeyTower, CannonTower, OctoTower... and some other classes uses the instanceOf to compare.

Here's an example of a class that uses the instanceOf:

BloonsTower.java

public void mousePressed(Point p) {
        Tower t = null;
        selectedTower = towerInfo[ insertTowerIdx ].getTower();

        if( selectedTower instanceof MonkeyTower )
            t = tCreator.createMonkey();
        else if( selectedTower instanceof OctoTower )
            t = tCreator.createOctogonal();
        else if( selectedTower instanceof CannonTower )
            t = tCreator.createCannon();
        else if( selectedTower instanceof MortarTower )
            t = tCreator.createMortar();
        setMoney( money - towerInfo[ insertTowerIdx ].getPrice() );
        t.setPosition( p );
        world.addTower(t);
        currentState = new SelectTowerState();
    }

ManipulatorCreator.java

if( t instanceof MonkeyTower )
        return null;
    else if( t instanceof OctoTower )
        return new OctoManipulator( t );
    else if( t instanceof CannonTower )
        return null;
    else if( t instanceof MortarTower )
        return new MortarManipulator( (MortarTower)t );
    return man;

And GameWriter:

public void saveFile( File file, int round, int money, int lives, World m ) throws IOException {
    PrintWriter out = new PrintWriter( new BufferedWriter( new FileWriter( file) ) );

    out.println( round );
    out.println( money );
    out.println( lives );
    Tower []torres = m.getTowers();
    out.println( torres.length );   // escrever o nº de torres
    for( Tower t : torres ){
        Point p = t.getComponent().getPosicao();
        // escrever a posição e o tipo de torre
        out.print(p.x+"\t" + p.y+"\t" );
        if( t instanceof MonkeyTower )
            out.println( "macaco" );
        else if( t instanceof OctoTower )
            out.println( "octo" );
        else if( t instanceof CannonTower )
            out.println( "canhao" );
        else if( t instanceof MortarTower )
            out.println( "morteiro" );
    }

    out.close();
}

What i've created is a class for visitor that visits every tower:

public class TowerVisitor implements Visitor{

    public void visit(MonkeyTower monkey) {
        // TODO Auto-generated method stub
    }

    public void visit(CannonTower cannon) {
        // TODO Auto-generated method stub
    }

    public void visit(MortarTower mortar) {
        // TODO Auto-generated method stub
    }

    public void visit(OctoTower octo) {
        // TODO Auto-generated method stub
    }
}

And, in each tower I've created has a method accept that returns itself

Now, I'm stuck in what to put inside the method visit and how to use the pattern to switch all the instanceOf's.

Thanks.

Community
  • 1
  • 1

2 Answers2

1

You should use core Object Oriented Programming patterns, namely inheritance, not a visitor pattern. You have several different types of towers, and similar actions (create, manipulate, toString, etc.) that should be implemented differently for each type of tower. A classic example of inheritance.

public abstract class Tower {
  public abstract Tower create();
  public abstract Manipulator manipulate();
}

---

public class MortarTower extends Tower {
  @Override
  public MortarTower create() {
    return new MortarTower();
  }

  @Override
  public MortarManipulator manipulate() {
    return new MortarManipulator(this);
  }

  @Override
  public String toString() {
    return "morteiro";
  }
}

---

public void mousePressed(Point p) {
  selectedTower = towerInfo[insertTowerIdx].getTower();
  setMoney(money - towerInfo[insertTowerIdx].getPrice());
  Tower t = selectedTower.create();
  t.setPosition(p);
  world.addTower(t);
  currentState = new SelectTowerState();
}

And so on.

dimo414
  • 44,897
  • 17
  • 143
  • 228
  • 1
    Note that the Visitor Pattern _is_ OOP. – jaco0646 Jan 08 '16 at 14:13
  • Of course you're right. I trust you know what I mean, though. Can you suggest a better way of phrasing it? "Core OOP"? "Basic OOP"? – dimo414 Jan 08 '16 at 17:51
  • If the intent was to follow @ravindra's comment and implement the [Factory Method pattern](https://sourcemaking.com/design_patterns/factory_method) then I would phrase it as, "_You should use the Factory Method pattern, not the Visitor pattern._" – jaco0646 Jan 08 '16 at 19:17
  • At least from what I've seen, I don't see a need for factories; I'm simply suggesting method overriding in subclasses. – dimo414 Jan 08 '16 at 19:56
  • this is a project for university... i cant compare strings to check if it's a monkey tower or a cannon tower. The main objective of this project is to use patterns to avoid some code. this is one of the places where a pattern (or more than one) should be used. – user1987003 Jan 09 '16 at 13:09
  • Where am I suggesting you do string comparisons? Inheritance *is* a pattern. – dimo414 Jan 09 '16 at 17:32
  • @user1987003 His answer uses the [factory pattern](https://en.m.wikipedia.org/wiki/Factory_method_pattern#Example_implementations). Also, you should never force design patterns. Design patterns are there to solve problems. Forcing these patterns could result in misuse of them, which may lead to more problems – Dioxin Jan 09 '16 at 17:41
0

You have to use FactoryMethod orAbstractFactory pattern (If you want to createe ManipulatorDactory independemt of Tower) instead of Visitor.

Have a look at this Factory Method and Abstract Facotry for more details.

Some sample code:

public class FactoryMethodDemo{

    public FactoryMethodDemo(){

    }
    public Tower getTower(String type){
        if ( type.equalsIgnoreCase("monkey")){
            return new MonkeyTower();
        }else if ( type.equalsIgnoreCase("octo")){
            return new OctoTower();
        }else if ( type.equalsIgnoreCase("canon")){
            return new CannonTower();
        }else if ( type.equalsIgnoreCase("mortal")){
            return new MortarTower();
        }
        return null;
    }
    public static void main(String args[]){
        FactoryMethodDemo factory = new FactoryMethodDemo();
        Tower tower = factory.getTower(args[0]);
        System.out.println("Tower:"+tower);
    }
}
abstract class Tower{
    Manipulator manipulator = null;
    public Tower(){

    }
    public String toString(){
        return this.getClass().getSimpleName()+":manipulator:"+manipulator;
    }
    public Manipulator getManipulator(){
        return manipulator;
    }
}
class MonkeyTower extends Tower{
    public MonkeyTower(){

    }
}
class OctoTower extends Tower{
    public OctoTower(){
        manipulator = new OctoManipulator();
    }

}
class CannonTower extends Tower{
    public CannonTower(){

    }
}
class MortarTower  extends Tower{
    public MortarTower(){
        manipulator = new MortarManipulator();
    }

}
class Manipulator{

}
class OctoManipulator extends Manipulator{

}
class MortarManipulator extends Manipulator{

}

output:

D:\Study\Java>java FactoryMethodDemo monkey
Tower:MonkeyTower:manipulator:null

D:\Study\Java>java FactoryMethodDemo mortal
Tower:MortarTower:manipulator:MortarManipulator@4187a8e0

D:\Study\Java>java FactoryMethodDemo octo
Tower:OctoTower:manipulator:OctoManipulator@46fb3d6

D:\Study\Java>java FactoryMethodDemo canon
Tower:CannonTower:manipulator:null

Related SE questions :

Factory Pattern. When to use factory methods?

What is the basic difference between the Factory and Abstract Factory Patterns?

Community
  • 1
  • 1
Ravindra babu
  • 45,953
  • 8
  • 231
  • 206
  • the abstract factory shouldn't be used when we want to create a different types of famillies ? we are working with only a type -> tower. in this case we need to return new objects of towers, right? but, not in all cases. i was thinking on continue with visitor, but for the cases that needs to return a new object, implement a prototype – user1987003 Jan 09 '16 at 13:38
  • My answer implemented only FactoryMethod pattern. Concrete tower is returning proper manipulator object. I have handled the conditions you quoted in question. – Ravindra babu Jan 09 '16 at 13:58