【问题标题】:Avoid Using InstanceOf with Visitor Pattern - Java避免将 InstanceOf 与访客模式一起使用 - Java
【发布时间】:2016-01-08 00:16:20
【问题描述】:

我在 Stack Overflow 上搜索了这个 subjet arround。我找到了以下解决方案:

Explanation of Visitor Pattern

现在,我的情况与此类似。但是,我需要避免使用“instanceOf”。

我有一个游戏,其中包含名为 MonkeyTowerCannonTowerOctoTower... 的塔,其他一些类使用 instanceOf 进行比较。

这是一个使用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;

还有游戏作家:

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

我创建的是一个访问每个塔的访客类:

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

而且,在我创建的每个塔中,都有一个方法 accept 返回自身

现在,我陷入了在方法 visit 中放入什么以及如何使用该模式来切换所有 instanceOf 的问题。

谢谢。

【问题讨论】:

  • 我不明白您为什么需要访问者模式。为什么不创建抽象方法:Tower.createTower()Tower.createManipulator() 等?
  • 你需要 FactoryMethod 模式而不是访问者。
  • 我认为我不需要工厂。所有的对象都是塔,如果它们是不同的塔,它们独立地实现相同的接口

标签: java design-patterns factory-pattern instanceof visitor-pattern


【解决方案1】:

您应该使用核心Object Oriented Programming 模式,即继承,而不是访问者模式。您有几种不同类型的塔,以及类似的操作(创建、操作、toString 等),每种类型的塔应该以不同的方式实现。继承的经典示例。

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

等等。

【讨论】:

  • 请注意,访问者模式 OOP。
  • 当然你是对的。不过,我相信你知道我的意思。你能推荐一个更好的表达方式吗? “核心面向对象”? “基本 OOP”?
  • 如果意图遵循@ravindra 的评论并实施Factory Method pattern,那么我将其表述为,“您应该使用工厂方法模式,而不是访问者模式。"
  • 至少从我所见,我认为不需要工厂;我只是建议在子类中覆盖方法。
  • 这是一个大学项目...我无法比较字符串来检查它是猴子塔还是炮塔。这个项目的主要目标是使用模式来避免一些代码。这是应该使用模式(或多个模式)的地方之一。
【解决方案2】:

您必须使用FactoryMethodAbstractFactory 模式(如果您想创建独立于 Tower 的 ManipulatorDactory)而不是 Visitor。

查看Factory MethodAbstract Facotry 了解更多详情。

一些示例代码:

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{

}

输出:

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

相关的 SE 问题:

Factory Pattern. When to use factory methods?

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

【讨论】:

  • 当我们想创建不同类型的家庭时,不应该使用抽象工厂吗?我们只使用类型 -> 塔。在这种情况下,我们需要返回新的塔对象,对吧?但是,并非在所有情况下。我正在考虑继续访问访问者,但是对于需要返回新对象的情况,请实现原型
  • 我的答案只实现了 FactoryMethod 模式。混凝土塔正在返回正确的机械手对象。我已经处理了您所引用的条件。
猜你喜欢
  • 2011-09-03
  • 2013-03-05
  • 2012-04-18
  • 2022-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-13
  • 1970-01-01
相关资源
最近更新 更多