将超类作为参数传递给期望子类的方法

5

我有一个对象树,看起来像这样:

           Ball
          /    \
  LegalBall    IllegalBall

我有两种方法:

class o {
AddBall(LegalBall l)
AddBall(IllegalBall i)
}

在另一个类中,我想要做如下操作:

o.AddBall(myBall);

其中myBall是Ball类型。并根据子类型调用正确的方法。

显然我做不到这一点……参数不适用。

有人知道我如何实现我的目标吗?或者是否有好的解决方法?

谢谢

编辑:我正在尝试构建一个板球记分卡类型的应用程序。因此,根据投掷的球类型,各种其他元素应该发生变化。

我的最初意图是能够从某种形式的UI中指定球类型和得分,然后从BallFactory创建适当类型的球,例如当我向团队得分发送无球时,它将把值添加到团队得分上,但也将该值添加到无球计数器上。但是当我将同样的球交给Batsmens Analysis处理时,它只会将值-1计入击球手的总分中。

希望这不是对我的最初意图的太糟糕的解释。

7个回答

6
您可以使用访问者模式
class Basket {
    void AddBall(LegalBall l) {
        System.out.println("LegalBall added to basket");
    }

    void AddBall(IllegalBall i) {
        System.out.println("IllegalBall added to basket");
    }
}

interface Ball {
    void AddBall(Basket b);
}

class LegalBall implements Ball {
    void AddBall(Basket b) {
        b.AddBall(this);
    }
}

class IllegalBall implements Ball {
    void AddBall(Basket b) {
        b.AddBall(this);
    }
}

或者更加通用地说:
interface BallVisitor {
    void visit(LegalBall l);
    void visit(IllegalBall i);
}

interface Ball {
    void accept(BallVisitor v);
}

class LegalBall implements Ball {
    void accept(BallVisitor v) {
        v.visit(this);
    }
}

class IllegalBall implements Ball {
    void accept(BallVisitor v) {
        v.visit(this);
    }
}

class Basket implements BallVisitor {
    void visit(LegalBall l) {
        System.out.println("LegalBall added to basket");
    }

    void visit(IllegalBall i) {
        System.out.println("IllegalBall added to basket");
    }
}

我需要将AddBall应用于不止Basket这一个对象,还有其他一些对象。我是否需要为每种类型实现一个添加球的方法? - Rocco
在一个普通的接口中添加“visit”和“accept”方法会显得非常奇怪。 - Tom Hawtin - tackline

4

你应该尽量只实现一个方法:

class o {
AddBall(Ball b)
}

尝试依赖多态性以实现对不同类别的不同行为。当然,具体细节取决于Ball层次结构的实现。


0

使用访问者模式。不使用它很麻烦,这也是这个问题的主题:在没有双重分派/访问者模式的情况下解决Java的静态方法调度

然而,您能否说明一下您最初的问题?我的意思是,为什么您需要为Add方法拥有这两个重载版本?也许您可以通过完全不依赖于动态分派(如访问者模式)的完全不同的方式来解决它?


0

你可能(或者可能不)想要使用访问者模式的一部分。

Ball 中添加一个方法:

public abstract void addTo(o o);

LegalBallIllegalBall 中实现为

public void addTo(o o) {
    o.add(this);
}

0

好的,以上提到了访问者模式。如果你不能或不想修改 Ball、LegalBall 或 IllegalBall,那么你可以尝试基于球的类型有一个单一的方法分支。请注意,如果您稍后添加一个 QuasiLegalBall,此代码将会崩溃。你所提到的一般情况很难处理,因为 LegalBall 和 IllegalBall 的存在并不意味着没有符合你所描述的这两种类型之外的其他球(至少从语言的角度来看)。

class o {
    public void AddBall(Ball b) 
    { 
        if (b instanceof LegalBall) {AddLegalBall(b); }
        else if (b instanceof IllegalBall) {AddIllegalBall(b); }
        else { /*error, new type of ball created*/ }
    }
    private void AddLegalBall(LegalBall b) { }
    private void AddIllegalBall(IllegalBall b) { }
    }
 }

-1

访问者模式以及使用回调的类似解决方案,似乎只是试图弯曲您的代码,以使编译器接受您有缺陷的类层次结构。

我会保留类型Ball,并将合法/非法作为该类型的属性。您只需要o.add(Ball),在其中基于某些属性或通过方法isLegal()检查合法/非法即可。

如果上述方法似乎不合理,则同时添加两个(非常)不同类型的单个方法是不合理的,您提出的子类型关系也不是正确的方法。


-1

我同意使用 Visitor。

此外,如果您没有访问 Ball 层次结构(源代码访问)或者只是不想修改那里的任何内容;您可以修改客户端类并从那里决定。

当然,不好的一点是你最终会有很多 if/elseif 语句。

您需要添加通用方法(add(Ball)),然后从那里调用其他方法。这很快速、简单和粗略。

:)

public class Test {
    public static void main( String [] args ) { 
        Ball ball = new IllegalBall();
        Test test = new Test();
        test.add( ball );
        test.add( new IllegalBall() );
        test.add( new LegalBall() );
    }
    private void add( Ball ball ){
        System.out.println("Generic method: I'll have someone handling this : "  + ball );
        if( ball instanceof IllegalBall ) {
            add( ( IllegalBall ) ball );
        } else if( ball instanceof LegalBall ) {
            add( ( LegalBall ) ball );
        }
    }
    private void add( IllegalBall ball ){
        System.out.println("illega-ball: I won't do anything about it! " + ball );
    }
    private void add( LegalBall ball ) { 
        System.out.println("legal-ball: Hey this is legal I'll do my best!! " + ball );
    }
}

class Ball {}
class IllegalBall extends Ball {}
class LegalBall extends Ball {}

顺便提一下,如果您没有直接的引用,编译器会将其发送到正确的方法中,就像最后两个调用一样。

正如您所看到的,您只需要添加以下代码:

private void add( Ball ball ){
    System.out.println("Generic method: I'll have someone handling this : "  + ball );
    if( ball instanceof IllegalBall ) {
        add( ( IllegalBall ) ball );
    } else if( ball instanceof LegalBall ) {
        add( ( LegalBall ) ball );
    }
}

糟糕。这是"instanceof"和方法重载作为不良设计代码异味的教科书式例子。您正在滥用类型系统。 - eljenso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接