所以如果我有4个类都是抽象超类运动员派生的,并且每个类都有一个方法种族()。
课程分别是Runner,Swimmer,Hurdler和TriAthlete。
还有抽象的比赛'延伸到Race,HurdleRace和SwimRace的类。
现在,我希望Runner和Swimmer以及Hurdler都有一个race()方法,根据运动的内容返回一个随机数...所以10-20s用于跑步,20-30s用于跨栏,30- 40s游泳。
现在铁人三项运动员可以参加三种比赛中的任何一种,但我显然希望他们随机返回的值取决于种族的类型。实现这个的最佳方法是什么?
我认为使用接口会有所帮助,但我不知道它会如何?
我可以附加代码,但我意识到id只是附加了很多而且问题实际上是概念性的 - 更多关于我对面向对象编程的理解。
谢谢!
答案 0 :(得分:2)
<强> 1。选项1
您可以尝试对真实的&#39;进行建模。将对象转换为Java类。 真正的运动员通常参加比赛 - &gt;运动员课程应该掌握与运动员相关的信息(例如他在一个好日子里的速度),并且应该知道参加比赛(有一种方法可以允许)。 比赛具有某些属性(例如,长度;完成时间应根据此属性而变化) - &gt;比赛班应该掌握与比赛有关的信息。
abstract class Athlete {
public abstract int participate(Race raceToParticipateInto);
}
但是,正如您所指定的,您希望拥有多种类型的比赛和运动员,因此通过使用上面的签名,您将编写一个非常糟糕的API。您应该专注于编写不允许客户犯错误的API。你不想让正在使用你的类的其他程序员做出类似的事情:
Runner runner = new Runner();
SwimRace swimmingRace = new SwimRace();
runner.participate(swimmingRace); -> this should be a compilation error.
为了解决此问题,您可以使用泛型。
abstract class Athlete<T extends Race> {
public abstract int participate(T race);
}
当您扩展课程时,您可以指定运动员可以参加的确切种族类型(因此方法签名可以防止编译时出错):
class Runner extends Athlete<RunningRace> {
public abstract int participate(RunningRace race);
}
您可以将TriAthlete类定义为接受任何类型种族的Athlete子类型:
class TriAthlete extends Athlete<Race> {
public abstract int participate(Race race);
}
但是你会遇到与上面相同的问题(如果你想要一个知道如何参加2种比赛的运动员子类型,你的API将如何防止其他程序员犯错误怎么办?)。
<强> 2。选项2
我看到的另一种方法是为运动员编写多个界面:
public interface Athlete {}
public interface RunnerAthlete extends Athlete {
int participate(RunningRace race);
}
public interface SwimmerAthlete extends Athlete {
int participate(SwimmingRace race);
}
并为他们实施如下:
public class RunnerAthleteImpl implements RunnerAthlete {
int participate(RunningRace race) {}
}
public class TriAthleteImpl implements RunnerAthlete, SwimmerAthlete, HurdlerAthlete {
int participate(RunningRace race) {}
int participate(SwimmingRace race) {}
int participate(HurdleRace race) {}
}
你偏离初始方法。此解决方案有优点和缺点:您编写更多代码但接口很简单。此外,通过拥有太多的课程/界面,您可能有可能使您的图书馆&#39;更难为新程序员学习。
第3。选项3。
在企业应用程序中,在模型类中添加逻辑被认为是一种不好的做法(可论证 - 请参阅http://en.wikipedia.org/wiki/Anemic_domain_model)。模型类(运动员,种族)应仅包含描述实体所需的信息(例如,您需要知道比赛的长度和运动员的速度才能返回合理的结果)以及此类领域的获取者/设定者。 因此,类似于参与的方法(种族r)&#39;耦合这两个类(运动员不仅知道Race类,而且还实现了逻辑 - 生成随机结果)。
你可以有简单的模型类,只有getter和setter,它们以类似于Option 2的方式扩展接口,并且有一个&#39; service&#39;具有组织比赛逻辑的类:
class CompetitionOrganizerService<A extend Athlete, R extends Race> {
public List<Result> organize(List<A> participants, R competition);
}
其中,结果可以是一个类,其中包含运动员和代表该运动员结果的int值之间的配对。
答案 1 :(得分:1)
由于你还在为一个种族使用一个特定的类,似乎最好将Athlete
的每个子类作为一个实例变量赋予它自己的Race
对象 - 所以a Race
的{{1}},Runner
的{{1}},依此类推,SwimRace
的所有三场比赛。然后让每个Swimmer
子类都有一个方法来生成比赛时间。然后,每个TriAthlete
子类可以询问其自己的Race
对象的时间,Athlete
可以询问其三个对象中的每个对象的时间。
答案 2 :(得分:0)
怎么样:
abstract class Race {
int minScore, maxScore;
// set those values in the constructor
// add getter methods (int getMinScore, int getMaxScore)
}
class SwimRace {
SwimRace() {
super(30, 40);
}
}
class Athlete {
int race(Race race) {
// maybe first validate that this athlete can compete in this type of race?
int min = race.getMinScore(), max = race.getMaxScore();
return min + (int)(Math.random() * (max-min));
}
}