有两种方法可以处理这种用例:
1.实现多分派:
首先创建Curve
一个接口并将两个重载版本添加intersect
到该接口,从而使它们成为合同的一部分。接下来,让intersection(Curve c)
每个子类中的方法将调用委托给适当的重载表单。(又名访客模式)
interface class Curve {
public Point[] intersection(Curve c);
public Point[] intersection(Line l);
public Point[] intersection(Arc c);
}
class Line extends Curve {
public Point[] intersection(Curve c) {
return c.intersection(this);
}
@Override
public Point[] intersection(Line l) {
System.out.println("line interesection with line");
return new Point[0];
}
@Override
public Point[] intersection(Arc c) {
System.out.println("line intersection with arc");
return new Point[0];
}
}
class Arc extends Curve {
public Point[] intersection(Curve c) {
return c.intersection(this);
}
@Override
public Point[] intersection(Line l) {
System.out.println("arc interesection with line");
return new Point[0];
}
@Override
public Point[] intersection(Arc c) {
System.out.println("arc interesection with arc");
return new Point[0];
}
}
然后,您可以在类中调用您的intersection
方法,Intersection
而无需任何显式强制转换:
public class Intersection {
public static boolean intersect(ArrayList<Curve> list1,
ArrayList<Curve> list2) {
for (Curve i : list1) {
for (Curve j : list2) {
if (i.intersection(j).length > 0)
return true;
}
}
return false;
}
public static void main(String[] args) {
Curve line1 = new Line();
Curve arc1 = new Arc();
Curve line2 = new Line();
Curve arc2 = new Arc();
ArrayList<Curve> list1 = new ArrayList<>();
ArrayList<Curve> list2 = new ArrayList<>();
list1.add(line1);
list1.add(arc1);
list2.add(line2);
list2.add(arc2);
Intersection.intersect(list1, list2);
}
}
Extras:看看这种实现访问者模式的替代方法。
2. 使直线和曲线遵守同一个界面(契约):
如果Line
并Arc
坚持 的接口Curve
,您的代码将不再需要该intersect
方法的重载版本。如果我们说 a Line
是 aCurve
并且 anArc
也是 a Curve
,那么这两个类都应该具有相同的接口(我所说Curve
的接口是指它们支持的操作列表)。如果这些类没有与 相同的接口Curve
,这就是问题所在。中存在的方法应该是和类Curve
应该需要的唯一方法。Line
Arc
有几种策略可以消除子类具有超类中不存在的方法的需要:
- 如果与超类相比,子类需要额外的输入,请通过构造函数提供这些输入,而不是创建对这些输入进行操作的单独方法。
- 如果子类需要超类不支持的其他行为,请通过组合(阅读策略模式)支持此行为,而不是添加方法来支持其他行为。
一旦您消除了在子类中使用超类中不存在的专用方法的需要,您的代码就会自动消除对进行instanceof
检查或类型检查的需要。这符合Liskov 替换原则。