改变 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 层次结构,并提供动态实现(访问者模式)。
这取决于您的用例。
如何去掉运算符"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 层次结构,并提供动态实现(访问者模式)。
这取决于您的用例。