实现子类的通用类

huangapple go评论57阅读模式
英文:

implement generic class of child classes

问题

我创建了一个运动员(Athlete)类。

public class Athlete {
    private final int id;
    private final String name;
    private final Country sourceCountry;

    public Athlete(int id, String name, Country sourceCountry){
        this.id = id;
        this.name = name;
        this.sourceCountry = sourceCountry;
    }
}

然后我创建了以下接口和子类:

public interface IJumper {
    public double jump();
}

public interface IRunner {
    public double run();
}
public class Runner extends Athlete implements IRunner {


    public Runner(int id, String name, Country sourceCountryCode) {
        super(id, name, sourceCountryCode);
    }

    @Override
    public double run() {
        return Math.random();
    }
}

public class Jumper extends Athlete implements IJumper {

    public Jumper(int id, String name, Country sourceCountry) {
        super(id, name, sourceCountry);
    }

    @Override
    public double jump() {
        return Math.random();
    }

}

此外,我创建了以下的RunnerJumper类,以创建另一种既能跑又能跳的运动员:

public class RunnerJumper extends Athlete implements IRunner, IJumper {


    public RunnerJumper(int id, String name, Country sourceCountry) {
        super(id, name, sourceCountry);
    }

    @Override
    public double jump() {
        return Math.random();
    }

    @Override
    public double run() {
        return Math.random();
    }
}

现在,我想创建一个Team类。这个团队可以是跑步者或跳高者的团队(跑步者团队可以包含Runner和RunnerJumper,跳高者团队可以包含Jumper和RunnerJumper),所以我希望团队是泛型的。

此外,Team类应该有一个名为"compete"的方法(类似于:对于Team的每个Athlete:跑步或跳高,取决于运动员的类型...)。

我该如何实现这种行为?

我尝试按以下方式创建它:

public class Team<C extends Athlete> {}

但是在这种形式中,跑步者团队无法包含RunnerJumper。

我还尝试创建新的接口Competitor:

interface Competitor {}

并让IRunner和IJumper都扩展它。

这一开始看起来不错:

public class Team<C extends Competitor> {}

但我不明白如何在这种形式中实现compete功能...

英文:

I created an Athlete class.

public class Athlete {
    private final int id;
    private final String name;
    private final Country sourceCountry;

    public Athlete(int id, String name, Country sourceCountry){
        this.id = id;
        this.name = name;
        this.sourceCountry = sourceCountry;
    }
}

then I created the following interfaces and sub classes:

public interface IJumper {
    public double jump();
}

public interface IRunner {
    public double run();
}
public class Runner extends Athlete implements IRunner {


    public Runner(int id, String name, Country sourceCountryCode) {
        super(id, name, sourceCountryCode);
    }

    @Override
    public double run() {
        return Math.random();
    }
}

public class Jumper extends Athlete implements IJumper {

    public Jumper(int id, String name, Country sourceCountry) {
        super(id, name, sourceCountry);
    }

    @Override
    public double jump() {
        return Math.random();
    }

}

in addition, I created the following RunnerJumper class to create another type of athlete that can both run and jump:

public class RunnerJumper extends Athlete implements IRunner, IJumper {


    public RunnerJumper(int id, String name, Country sourceCountry) {
        super(id, name, sourceCountry);
    }

    @Override
    public double jump() {
        return Math.random();
    }

    @Override
    public double run() {
        return Math.random();
    }
}

now, I want to create an Team class. the team should be team of runners or jumpers (team of runners can contain Runner & RunnerJumper and team of Jumpers can contain Jumper & RunnerJumper)
so I want the team to be generic..
in addition the team class should have method like "compete" (
something like: forEach Athlete of Team:
run or jump (depends the type of athlete..)
)

how can I achieve this kind of behaviour?

I tried to create it like this:

public class Team&lt;C extends Athlete&gt; {}

but in this form team of runners cannot contain RunnerJumper..
I also tried to create new interface Competitor:

interface Competitor {}

and have both IRunner & IJumper extend it..
this seems good at first:

public class Team&lt;C extends Competitor&gt; {}

but I don't understand how I can Implement the compete functionality in this form...

答案1

得分: 1

这是翻译后的内容:

这样做是不可能的,就像你所想象的那样。

在Java中,类型用于表示保证。对于代码片段,有一些是百分之百确定的。如果一段代码得到一个“Duck”,那么可以百分之百确定它也是“Bird”和“Animal”。

但是你无法表达诸如“它要么是Duck要么是Bucket”这样的关系。你需要它们都扩展相同的超类型,并确保该类型仅被这两个扩展;一般情况下,这将需要多重继承和封闭类型。

而且你无法表达将值与类型混合的关系,比如“如果numberOfLegs == 8,那么类型就是Octopus”。我不知道如何称呼这种所需的装置,但我认为TypeScript中的结构类型可以表达这种约束。我认为鸭子类型是前提条件。

回到Java:如果有一组对象可以包含RunnerRunnerJumper,在Java的类型系统中唯一能保证的是所有对象都是Runner。没有泛型、继承等可以改变这一点。

你可以使用众多模式之一来实现你的业务目标:

  1. 将跳跃/奔跑行为重构为单独的类,两者都实现了带有单个perform方法的Action接口。然后创建一个接口,其中只有一个方法:getActions,称为Player。然后,你的Team可以迭代Player,为每个玩家获取动作,并在内部循环中调用其perform方法。getAction方法的实现甚至可以返回静态的lambda列表,这样你甚至可以从内部访问所有玩家的属性。这种模式允许你保持可能动作的列表是开放的(引入新的动作将不需要重新编译或触及你的Team类)。

  2. 如果Team静态地知道可能的动作列表,你可以使用“访问者”模式-让Team调用玩家的“visit”方法,玩家可以调用Team的“playerJumps(Jumper j)”或“playerRuns(Runner r)”。

或者你可以使用语言的其他机制:反射和类型转换(这也会使可能的动作列表变得静态)。

英文:

It's impossible to do it the way you imagine.

Types - in Java - serve to express guarantees. Things that are 100% certain about a piece of code. If a piece of code gets a Duck, there is 100% guarantee that it is also a Bird and an Animal.

But you cannot express relations like "it's either a Duck or a Bucket". You would need both to extend the same supertype and make sure that the type is only extended by these two; in general it would require multiple inheritance and sealed types.

And you cannot express relations which mix values with types, like "if the numberOfLegs == 8, then the type is Octopus". I have no idea how to call the aparatus required for this, but the structural types in Type Script, I think, can express such constraints. I think that duck typing is a prerequisite.

Coming back to Java: if there's a set of objects which can contain Runners or RunnerJumpers, the only thing that you can guarantee in the Java's type system is that all the objects are Runners. No generics, inheritance etc. can change that.

You can use one of the multitude of patterns to achieve your business goal:

  1. refactor the jumping / running behavior into a separate classes, both implementing Action with a single perform method. Then create an interface with a single method: getActions, called, say, a Player. Then, your Team can iterate over Players, get actions for each one and call their perform method in an inner loop. The implementation of the getAction method can even return a static list of lambdas, so that you can access all your player's attributes from inside. This pattern allows you to keep the list of possible actions open (introducing new actions will not require you to recompile or touch your Team class).

  2. if the list of possible actions is statically known by the Team, you can use the Visitor pattern - let the Team call the player's visit method, and the player can call Team's playerJumps(Jumper j) or playerRuns(Runner r).

Or you can use other mechanisms of the language: reflection and casting (this will also make the list of possible actions static).

答案2

得分: 0

你可以创建两个团队类,一个用于跑步者,一个用于跳高者,如下所示:

public interface Team {
    public void compete();
}

public class TeamRunners implements Team {
    private List<Runner> runners;
    private List<RunnerJumper> runnerJumpers;

    public TeamRunners(List<Runner> runners, List<RunnerJumper> runnerJumpers) {
        this.runners = runners;
        this.runnerJumpers = runnerJumpers;
    }

    @Override
    public void compete() {
        for (Runner runner : runners) {
            runner.run();
        }
        for (RunnerJumper runnerJumper : runnerJumpers) {
            runnerJumper.run();
            runnerJumper.jump();
        }
    }
}

public class TeamJumpers implements Team {
    private List<Jumper> jumpers;
    private List<RunnerJumper> runnerJumpers;

    public TeamJumpers(List<Jumper> jumpers, List<RunnerJumper> runnerJumpers) {
        this.jumpers = jumpers;
        this.runnerJumpers = runnerJumpers;
    }

    @Override
    public void compete() {
        for (Jumper jumper : jumpers) {
            jumper.jump();
        }
        for (RunnerJumper runnerJumper : runnerJumpers) {
            runnerJumper.run();
            runnerJumper.jump();
        }
    }
}
英文:

What you could do is you could create two Team classes, one for the runners and one for the jumpers, like so:

public interface Team {
    public void compete();
}

public class TeamRunners implements Team {
    private List&lt;Runner&gt; runners;
    private List&lt;RunnerJumper&gt; runnerJumpers;

    public Team(List&lt;Runner&gt; runners, List&lt;RunnerJumper&gt; runnerJumpers) {
        this.runners = runners;
        this.runnerJumpers = runnerJumpers;
    }

    @Override
    public void compete() {
        for (Runner runner : runners) {
            runner.run();
        }
        for (RunnerJumper runnerJumper : runnerJumpers) {
            runnerJumper.run();
            runnerJumper.jump();
        }
    }
}

public class TeamJumpers implements Team {
    private List&lt;Jumper&gt; jumpers;
    private List&lt;RunnerJumper&gt; runnerJumpers;

    public Team(List&lt;Jumper&gt; jumpers, List&lt;RunnerJumper&gt; runnerJumpers) {
        this.jumpers = jumpers;
        this.runnerJumpers = runnerJumpers;
    }

    @Override
    public void compete() {
        for (Jumper jumper : jumpers) {
            jumper.jump();
        }
        for (RunnerJumper runnerJumper : runnerJumpers) {
            runnerJumper.run();
            runnerJumper.jump();
        }
    }
}

huangapple
  • 本文由 发表于 2020年10月9日 18:50:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/64278538.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定