如何摆脱 instanceof?
How to get rid of instanceof?
有人告诉我,在下面的代码中使用 instanceof 是一种不好的做法,因为它会变得重复并使扩展变得困难。不过,我对 Java 还是个新手,并不能马上看出我的替代方案是什么,你会建议我做什么来摆脱实例和抽象代码?
void moveit(Vehicle car) {
if(car instanceof Volvo240){
volvoPoint.x = (int) car.getXCoordinate();
volvoPoint.y = (int) car.getYCoordinate();
}
if(car instanceof Scania) {
scaniaPoint.x = (int) car.getXCoordinate();
scaniaPoint.y = (int) car.getYCoordinate() + 100;
}
if(car instanceof Saab95) {
saabPoint.x = (int) car.getXCoordinate();
saabPoint.y = (int) car.getYCoordinate() + 200;
}
repaint();
}
不知道完整的代码,并假设您只有这三个子class。侵入性最小的方法是利用方法重载:
void moveit(Volvo240 car){
volvoPoint.x = (int) car.getXCoordinate();
volvoPoint.y = (int) car.getYCoordinate();
repaint();
}
void moveit(Scania car){
volvoPoint.x = (int) car.getXCoordinate();
volvoPoint.y = (int) car.getYCoordinate() + 100;
repaint();
}
void moveit(Saab95 car){
saabPoint.x = (int) car.getXCoordinate();
saabPoint.y = (int) car.getYCoordinate() + 200;
repaint();
}
void moveit(Vehicle car){
repaint();
}
在我看来,变量volvoPoint.x
和volvoPoint.y
应该属于classVolvo240
(其他变量也一样)。但是您将这些变量(应该属于 classes Volvo240
、Scania
和 Saab95
)保存在一个地方,这样(我假设)您可以repaint
基于这些变量的值。
您应该考虑另一种方法,您 教导 每个 Vehicle
如何 repaint
自己。因此,将 repaint
逻辑和那些变量移动到每个子 classes,因此:
public class Volvo240 extends Vehicle{
public repaint(){
volvoPoint.x = (int) car.getXCoordinate();
volvoPoint.y = (int) car.getYCoordinate();
// do the repaint logic
}
}
InstanceOf 会使引入新型汽车变得困难。您将必须找到您进行这些 instanceof 检查的所有地方,并用新车进行修改。参见“对扩展开放,对修改关闭”的原则。
你应该有一个界面
interface Vehicle {
Integer getXCoordinate();
Integer getYCoordinate();
void moveIt(Point point);
}
以及三个实施方案,Saab95、Volvo240 和 Scania
class Saab95 implements Vehicle {
moveIt(Point point) {
point.x = getXCoordinate();
point.y= getYCoordinate() + 200
}
}
其他车以此类推
我要直接说,我对你原来的解决方案没有意见。更多相关信息,请参见此 post 的底部。如果您真的希望当前代码在不使用 instanceof
的情况下工作,这里有一种方法。
您可以创建一个新的 class 来存储与每种类型的车辆相关的信息,如下所示:
public class VehicleInfo {
private final Point point;
private final int offset;
public VehicleInfo(Point point, int offset) {
this.point = point;
this.offset = offset;
}
public Point getPoint() {
return point;
}
public int getOffset() {
return offset;
}
}
然后您可以像这样在您的方法中使用 class:
private static final HashMap<Type, Point> POINT_MAP = new HashMap<Type, Point>() {
{
put(Volvo240.class, new VehicleInfo(volvoPoint, 0));
put(Scania.class, new VehicleInfo(scaniaPoint, 100));
put(Saab95.class, new VehicleInfo(saabPoint, 200));
}
};
void moveit(Vehicle car) {
VehicleInfo info = POINT_MAP.get(car.getClass());
info.getPoint().x = car.getXCoordinate();
info.getPoint().y = car.getYCoordinate() + info.getOffset();
repaint();
}
也就是说,我对您使用 instanceof
的原始解决方案真的没有任何问题。该程序将不得不在某个时候检查参数的类型,因此最好在您的代码中明确显示。除非程序的这一部分将被反复修改,并且这是某个每个人都需要使用标准编码约定的大型项目的一部分,否则我会坚持使用你所拥有的,不管这里的其他人怎么说。最近有人向我介绍了 YAGNI 的概念,我认为这绝对适用于此。如果有效,那就有效。
有人告诉我,在下面的代码中使用 instanceof 是一种不好的做法,因为它会变得重复并使扩展变得困难。不过,我对 Java 还是个新手,并不能马上看出我的替代方案是什么,你会建议我做什么来摆脱实例和抽象代码?
void moveit(Vehicle car) {
if(car instanceof Volvo240){
volvoPoint.x = (int) car.getXCoordinate();
volvoPoint.y = (int) car.getYCoordinate();
}
if(car instanceof Scania) {
scaniaPoint.x = (int) car.getXCoordinate();
scaniaPoint.y = (int) car.getYCoordinate() + 100;
}
if(car instanceof Saab95) {
saabPoint.x = (int) car.getXCoordinate();
saabPoint.y = (int) car.getYCoordinate() + 200;
}
repaint();
}
不知道完整的代码,并假设您只有这三个子class。侵入性最小的方法是利用方法重载:
void moveit(Volvo240 car){
volvoPoint.x = (int) car.getXCoordinate();
volvoPoint.y = (int) car.getYCoordinate();
repaint();
}
void moveit(Scania car){
volvoPoint.x = (int) car.getXCoordinate();
volvoPoint.y = (int) car.getYCoordinate() + 100;
repaint();
}
void moveit(Saab95 car){
saabPoint.x = (int) car.getXCoordinate();
saabPoint.y = (int) car.getYCoordinate() + 200;
repaint();
}
void moveit(Vehicle car){
repaint();
}
在我看来,变量volvoPoint.x
和volvoPoint.y
应该属于classVolvo240
(其他变量也一样)。但是您将这些变量(应该属于 classes Volvo240
、Scania
和 Saab95
)保存在一个地方,这样(我假设)您可以repaint
基于这些变量的值。
您应该考虑另一种方法,您 教导 每个 Vehicle
如何 repaint
自己。因此,将 repaint
逻辑和那些变量移动到每个子 classes,因此:
public class Volvo240 extends Vehicle{
public repaint(){
volvoPoint.x = (int) car.getXCoordinate();
volvoPoint.y = (int) car.getYCoordinate();
// do the repaint logic
}
}
InstanceOf 会使引入新型汽车变得困难。您将必须找到您进行这些 instanceof 检查的所有地方,并用新车进行修改。参见“对扩展开放,对修改关闭”的原则。
你应该有一个界面
interface Vehicle {
Integer getXCoordinate();
Integer getYCoordinate();
void moveIt(Point point);
}
以及三个实施方案,Saab95、Volvo240 和 Scania
class Saab95 implements Vehicle {
moveIt(Point point) {
point.x = getXCoordinate();
point.y= getYCoordinate() + 200
}
}
其他车以此类推
我要直接说,我对你原来的解决方案没有意见。更多相关信息,请参见此 post 的底部。如果您真的希望当前代码在不使用 instanceof
的情况下工作,这里有一种方法。
您可以创建一个新的 class 来存储与每种类型的车辆相关的信息,如下所示:
public class VehicleInfo {
private final Point point;
private final int offset;
public VehicleInfo(Point point, int offset) {
this.point = point;
this.offset = offset;
}
public Point getPoint() {
return point;
}
public int getOffset() {
return offset;
}
}
然后您可以像这样在您的方法中使用 class:
private static final HashMap<Type, Point> POINT_MAP = new HashMap<Type, Point>() {
{
put(Volvo240.class, new VehicleInfo(volvoPoint, 0));
put(Scania.class, new VehicleInfo(scaniaPoint, 100));
put(Saab95.class, new VehicleInfo(saabPoint, 200));
}
};
void moveit(Vehicle car) {
VehicleInfo info = POINT_MAP.get(car.getClass());
info.getPoint().x = car.getXCoordinate();
info.getPoint().y = car.getYCoordinate() + info.getOffset();
repaint();
}
也就是说,我对您使用 instanceof
的原始解决方案真的没有任何问题。该程序将不得不在某个时候检查参数的类型,因此最好在您的代码中明确显示。除非程序的这一部分将被反复修改,并且这是某个每个人都需要使用标准编码约定的大型项目的一部分,否则我会坚持使用你所拥有的,不管这里的其他人怎么说。最近有人向我介绍了 YAGNI 的概念,我认为这绝对适用于此。如果有效,那就有效。