改变 instanceof 为多态

Change instanceof to polymorphism

如何去掉运算符"instanceof"并用多态代替? NamedPlace 和 DescribedPlace 都是主要 class 地方的子class。

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

        }

    }

}

唯一的方法是首先向您的基 class.

添加一个抽象方法,例如 doTheThing()

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

当然,NamedPlace 会实现该方法来执行以下操作:

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

和另一个 class 实现它来做

JOptionPane describedPane = new JOptionPane();
...

这在技术上可以满足您的要求,但它也不是一个非常优雅的解决方案。因为这两种方法在做完全不同的事情。

A 更多 合理的解决方案可能是你有一个抽象方法,例如 returns 一个(格式化的)字符串,然后被添加到一个(统一的)消息 window,或类似的东西。

多态性的要点是允许使用公共接口做 "similar" 事情。它无助于在同一个引擎盖下做完全不同的事情。

你可以给Place抽象方法并将实现添加到子classes。

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 class)。

如果您的 Place classes 不应该知道对点击的具体响应实现,那么您可以使用 visitor pattern,并将您的 Place 分开来自其响应实现的层次结构。

然后你可以为不同的情况提供不同的实现,你的 Place classes 将不会增长,也不会与越来越多的特定情况代码紧密耦合。

为此,请使用其他方法更新您的父级 class(我更喜欢使用界面)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);
            }
        });
    }
}

}

你的选择实际上是:

  • 在您的 classes 中固定执行响应,并且您可以通过添加更多响应(较早的响应)来扩展您的层次结构
  • 或者拥有固定的 classes 层次结构,并提供动态实现(访问者模式)。

这取决于您的用例。