2014-09-13 88 views
0

所以如果我有4個類都是抽象超類運動員的派生,並且每個類都有一個方法race()。如何實現多功能類

類是跑步者,游泳者,跨欄運動員和TriAthlete。

還有一個抽象的「Race」類,它可以擴展到Race,HurdleRace和SwimRace。

現在,我希望跑者和游泳者以及跨欄運動員都有一個比賽()方法,根據運動的不同,返回一個隨機數......所以10-20s跑步,20-30s跑步,30 -40s游泳。

現在鐵人三項運動員可以在三種類型的比賽中進行比賽,但我顯然希望他們的隨機返回值取決於比賽類型。實現這個最好的方法是什麼?

我認爲使用接口將有所幫助,但我不能看到它會怎麼樣?

我可以附加代碼,但我意識到id只是附加了很多,問題是真正的概念 - 更多關於我對面向對象編程的理解。

謝謝!

+0

當我試圖回答你的問題時,我發現自己對原始問題進行了逆向工程。你真的想做什麼?例如。有一組運動員和一場比賽名單1)每場比賽,找到一個可以參加的運動員名單; 2)讓運動員「比賽」,並根據每位運動員的個人技能制定他們的比賽時間; 3)找出並呈現個人比賽獲勝者; 4)找出並呈現triatletes中的贏家。這是接近你想要的嗎? – SnakE 2014-09-13 06:05:12

回答

2

1.選擇1

你可以嘗試 '真正的' 對象模型轉換爲Java類。 真正的運動員通常參加比賽 - >運動員班級應該掌握與運動員相關的信息(例如他的速度在一個愉快的一天),並且應該知道參加比賽(有一種方法可以做到這一點)。 一場比賽有一定的屬性(例如長度;完成的時間應該隨着這個屬性而變化) - >種族類應該保存與種族相關的信息。

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); 
} 

您可以定義三項全能運動員類作爲接受任何類型的比賽的運動員亞型:

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) {} 
} 

你偏離有點從最初的方法。這種解決方案有優點和缺點:你編寫更多的代碼,但接口很簡單。另外,如果你有太多的類/接口,你可能會冒險讓你的'庫'更難學習新的程序員。

3選項3

在企業應用程序被認爲是不好的做法,在模型類中添加邏輯(有爭議的 - 見http://en.wikipedia.org/wiki/Anemic_domain_model)。模型類(運動員,種族)應該只包含描述實體所需的信息(例如,您需要知道比賽的長度和運動員的速度以便返回合理的結果)以及此字段的獲取者/設置者。 因此像'int參與(Race r)'這樣的方法是耦合2個類(Athlete不僅知道Race類,還有邏輯實現 - 產生一個隨機結果)。

你可以有與如在選項2延伸接口以類似的方式,並具有保持組織種族的邏輯一「服務」類只getter和setter簡單模型類:

class CompetitionOrganizerService<A extend Athlete, R extends Race> { 
    public List<Result> organize(List<A> participants, R competition); 
} 

其中結果可以是包含運動員和表示該運動員結果的int值之間的配對的類。

1

既然你也使用特定類比賽,現在看來似乎會是最好給Athlete自己的Race對象的每個子類作爲一個實例變量 - 所以Runner一個Race,一個SwimRaceSwimmer等等,所有三場比賽爲TriAthlete。然後每個Race子類都有一個方法來產生比賽時間。然後,每個Athlete子類可以請求其自己的Race對象,並且TriAthlete可以詢問其三個對象的每個對象的時間。

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)); 
    } 
}