将instanceof更改为多态

时间:2018-08-15 13:46:47

标签: java swing polymorphism instanceof visitor-pattern

如何删除运算符“ instanceof”并将其替换为多态? NamedPlace和DescribedPlace都是主类Place的子类。

class RightClickListener extends MouseAdapter {

    @Override
    public void mouseClicked(MouseEvent mev) {           
        p = (Place) mev.getSource();

        if (mev.getModifiers() == InputEvent.BUTTON3_MASK) {
            if (p instanceof NamedPlace) {
                JOptionPane.showMessageDialog(null, p.getName() + " " + p.getPosition(), "Platsinfo: ", JOptionPane.INFORMATION_MESSAGE);
            }
            if (p instanceof DescribedPlace) {
                JOptionPane describedPane = new JOptionPane();
                describedPane.setMessage("Name: " + p.getName() + " " + p.getPosition() + "\n" + "Description: " + ((DescribedPlace) p).getDescription());
                describedPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
                JDialog dialog = describedPane.createDialog(p, "Platsinfo:");
                dialog.setVisible(true);
            }

        }

    }

}

3 个答案:

答案 0 :(得分:2)

您可以为Place提供抽象方法,并将实现添加到子类中。

abstract class Place {
    // ..
    public abstract void action();
}

class NamedPlace extends Place {
    public void action() {
            JOptionPane.showMessageDialog(null, p.getName() + " " + p.getPosition(), "Platsinfo: ", JOptionPane.INFORMATION_MESSAGE);
    }
}

class DescribedPlace extends Place {
    public void action() {
            JOptionPane describedPane = new JOptionPane();
            describedPane.setMessage("Name: " + p.getName() + " " + p.getPosition() + "\n" + "Description: " + ((DescribedPlace) p).getDescription());
            describedPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
            JDialog dialog = describedPane.createDialog(p, "Platsinfo:");
            dialog.setVisible(true);
    }
}

,然后在侦听器中使用它。

class RightClickListener extends MouseAdapter {

    @Override
    public void mouseClicked(MouseEvent mev) {           
        p = (Place) mev.getSource();

        if (mev.getModifiers() == InputEvent.BUTTON3_MASK) {
            p.action();
        }
    }
}

但是,根据Place的确切含义,这可能不是一个好主意(例如,如果它不是GUI类)。

答案 1 :(得分:0)

唯一的方法是首先向基类中添加一个像doTheThing()这样的抽象方法。

这样您就可以在该侦听器中简单地调用p.doTheThing()

当然,NamedPlace实现了该方法:

JOptionPane.showMessageDialog(null, p.getName() + " " + p.getPosition(), "Platsinfo: ", JOptionPane.INFORMATION_MESSAGE);

和另一个类实现它

JOptionPane describedPane = new JOptionPane();
...

从技术上讲,这可以满足您的要求,但这也不是一个很好的解决方案。由于这两种方法的作用确实不同。

一个 more 合理的解决方案可能是您有一个抽象方法,该方法例如返回一个(格式化的)字符串,然后将其添加到一个(统一的)消息窗口中,或类似的方法。

多态性的目的是允许使用通用接口执行“相似”的操作。在相同的环境下做完全不同的事情无济于事。

答案 2 :(得分:0)

如果您的Place类不知道单击的特定响应实现,则可以使用visitor pattern,并将Place层次结构与其响应实现分开。< / p>

然后,您可以针对不同情况提供不同的实现,并且Place类将不会增长,并且会与越来越多的情况特定代码紧密结合。

要实现此目的,请使用其他方法更新您的父类(我更喜欢使用接口)Place

public interface Place {
    void accept(Visitor visitor);
}

并实现它:

public final class NamedPlace {
    @Override
    public void accept(Visitor visitor) {
        visitor.visitNamedPlace(this);
    }
}

public final class DescribedPlace {
    @Override
    public void accept(Visitor visitor) {
        visitor.visitDescribedPlace(this);
    }
}

现在访问者界面将如下所示:

public interface Visitor {
    void visitNamedPlace(NamedPlace place);
    void visitDescribedPlace(DescribedPlace place);

}

访问者模式现已准备就绪。并在您的示例中使用它:

class RightClickListener extends MouseAdapter {

    @Override
    public void mouseClicked(MouseEvent mev) {           
        ((Place) mev.getSource()).accept(new Visitor() {
            @Override
            public void visitNamedPlace(NamedPlace p) {
                JOptionPane.showMessageDialog(null, p.getName() + " " + p.getPosition(), "Platsinfo: ", JOptionPane.INFORMATION_MESSAGE);
            }
            @Override
            public void visitDescribedPlace(DescribedPlace p) {
                JOptionPane describedPane = new JOptionPane();
                describedPane.setMessage("Name: " + p.getName() + " " + p.getPosition() + "\n" + "Description: " + ((DescribedPlace) p).getDescription());
                describedPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
                JDialog dialog = describedPane.createDialog(p, "Platsinfo:");
                dialog.setVisible(true);
            }
        });
    }
}

}

您的选择实际上是:

  • 既可以在类中固定实现响应,也可以通过添加更多类来扩展层次结构(较早的响应)
  • 或者具有固定的类层次结构,并动态提供实现(访客模式)。

这取决于您的用例。