考虑以下课程设计:
public class SuperType { };
public class SubType1 extends SuperType { };
public class SubType2 extends SuperType { };
public class SubType3 extends SuperType { };
public class Tuple {
SuperType t1;
SuperType t2;
public Tuple(SuperType t1, SuperType t2) {
this.t1 = t1;
this.t2 = t2;
}
public void DoSomething1() {
if((t1 instanceof SubType1) && (t2 instanceof SubType3))
switch(t1, t2);
else if((t1 instanceof SubType2) && (t2 instanceof SubType1))
t1.DoSomething();
else if( ... ) {
t1.DoSomething();
t2.DoSomething();
}
else if( ... )
// ...
}
public void DoSomething2() {
// basically the same
}
}
由于动作依赖于两种类型,因此我无法通过将方法移动到子类型来避免instanceof运算符。有没有办法可以改进我的设计,所以我可以避免使用instanceof?
我知道这里有很多类似的问题,但我想避免使用访问者,因为我有大约20个DoSomething() - 方法会导致9 * 20的visit()实现。
答案 0 :(得分:1)
在OO语言中执行此操作的正确方法是使用名为" double-dispatch" (Googlable,但维基百科的页面并不好)。
"追加"方法就是一个很好的例子:
class Super
{
abstract void appendTo(Super target);
abstract void append(Sub1 source);
abstract void append(Sub2 source);
}
class Sub1
{
void appendTo(Super target)
{
target->append(this); //calls the Sub1 overload
}
void append(Sub1 source)
{
... this is Sub1, source is Sub1 ...
}
void append(Sub2 source)
{
... this is Sub1, source is Sub2 ...
}
}
class Sub2
{
void appendTo(Super target)
{
target->append(this); //calls the Sub2 overload
}
void append(Sub1 source)
{
... this is Sub2, source is Sub1 ...
}
void append(Sub2 source)
{
... this is Sub2, source is Sub2 ...
}
}
答案 1 :(得分:0)
这是一个简单的解决方案选项,您可以使用Generics
作为类型安全& Polymorphism
在每个子类中执行操作行为
interface SuperType<T> { void doAction(); };
class SubType1 implements SuperType<SubType1> { public void doAction(){} };
class SubType2 implements SuperType<SubType2> { public void doAction(){} };
class SubType3 implements SuperType<SubType3> { public void doAction(){} };
class Tuple {
//if((t1 instanceof SubType1) && (t2 instanceof SubType3))
//passing params rather than instanceof checking
public void doSomething1CaseOne(SuperType<? extends SubType1> t1, SuperType<? extends SubType3> t3) {
if(t1 == null || t3 == null) {
throw new NullPointerException("Null Params!");
}
/**
* the method action here
* example: switch(t1, t2);
*/
}
//if((t1 instanceof SubType2) && (t2 instanceof SubType1))
public void doSomething1CaseTwo(SuperType<? extends SubType2> t2, SuperType<? extends SubType1> t1) {
if(t2 == null || t1 == null) {
throw new NullPointerException("Null Params!");
}
/**
* the method action here
* example: t1.doAction();
*/
}
... others methods
}
现在这里是一个将有效/无效参数传递给方法的示例:
Tuple tuple = new Tuple();
SuperType<SubType1> t1 = new SubType1();
SuperType<SubType2> t2 = new SubType2();
SuperType<SubType3> t3 = new SubType3();
tuple.doSomething1CaseOne(t1, t3); //valid typesafe compilation time
tuple.doSomething1CaseOne(t1, t2); //invalid typesafe compilation time
tuple.doSomething1CaseTwo(t2, t1); //valid typesafe compilation time
tuple.doSomething1CaseTwo(t1, t2); //invalid typesafe compilation time