Java通过设计避免instanceof

时间:2015-11-01 14:53:54

标签: java inheritance polymorphism

考虑以下课程设计:

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()实现。

2 个答案:

答案 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