2012-04-09 8 views
1

私はこのようなチーム/プレイヤーの関係をデザインしたいと思っています。すべてのプレーヤーが1つのチームに所属していますが、インターフェースを使って練習したいのでITeamとIAthleteを作ってからBasketballTeamとBasketballPlayerを作りました。 は、その後、私はこのコードを書いた:2つのインターフェイスと2つのクラスの関係。

public interface IAthlete 
{ 
    string GetName(); 
    string GetSport(); 
} 

public interface ITeam 
{ 
    void AddPlayer(IAthlete player); 
    IAthlete[] GetAthletes(); 
    string GetName(); 
    int GetNumberOfPlayers(); 
} 

public class BasketballPlayer:IAthlete 
{ 
    private string name; 

    public string GetName() 
    { 
     return this.name; 
    } 

    public string GetSport() 
    { 
     return "Basketball"; 
    } 

    public BasketballPlayer(string name) 
    { 
     this.name = name; 
    } 

    public void Run(int distance) 
    { 
     Console.WriteLine(this.name + " just ran " + distance.ToString() + " meters."); 
    } 

    public bool Shoot() 
    { 
     Console.WriteLine("Successful shot for " + this.name); 
     return true; 
    } 
} 

public class BasketballTeam: ITeam  
{ 
    BasketballPlayer[] players; 
    int numberOfPlayers; 
    private string name; 

    public void AddPlayer(BasketballPlayer player) 
    { 
     this.players[this.numberOfPlayers] = player; 
     this.numberOfPlayers++; 
    } 

    public IAthlete[] GetAthletes() 
    { 
     return this.players; 
    } 

    public string GetName() 
    { 
     return this.name; 
    } 

    public int GetNumberOfPlayers() 
    { 
     return this.numberOfPlayers; 
    } 

    public BasketballTeam(string name) 
    { 
     this.numberOfPlayers = 0; 
     this.name = name; 
     this.players = new BasketballPlayer[10]; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     BasketballTeam bt = new BasketballTeam("MyTeam"); 
     BasketballPlayer bp = new BasketballPlayer("Bob"); 

     bt.AddPlayer(bp); 

     foreach (BasketballPlayer player in bt.GetAthletes()) 
     { 
      Console.WriteLine(player.GetName()); 
     } 

     foreach (IAthlete a in bt.GetAthletes()) 
     { 
      Console.WriteLine(a.GetName()); 
     } 
    } 
} 

をしかし、私はこの使用しているので、それがコンパイルされません:私はそれを考えて、この

public void AddPlayer(IAthlete player) 

の代わりにBasketballPlayerで

public void AddPlayer(BasketballPlayer player) 

をBasketballPlayerはIAthleteなので、動作するはずです。 そして、私はIAthleteに変更した場合、私はこのような別のクラスにすることができます。

public class HockeyPlayer : IAthlete 
{ 
    private string name; 

    public string GetName() 
    { 
     return this.name; 
    } 

    public string GetSport() 
    { 
     return "Hockey"; 
    } 

    public HockeyPlayer(string name) 
    { 
     this.name = name; 
    } 

    public void Run(int distance) 
    { 
     Console.WriteLine(this.name + " just ran " + distance.ToString() + " meters."); 
    } 
} 

をして、私のメインでこれを行う:私はHockeyPlayerを追加しているので、論理的に間違っている

HockeyPlayer hp = new HockeyPlayer("Henry"); 
bt.AddPlayer(hp); 

バスケットボールチームそれはこれのようになっていると私はちょうどそれをしないように注意する必要がありますか?私は間違って何をしていますか?クラス図を使用してこれをどのように表示しますか?これは疎結合につながるか?

+0

これらのメソッドのほとんどではなく、プロパティを使用する必要があります。 – SLaks

答えて

2

あなたのコードにいくつかの考えです。まず、C#では、GetメソッドとSetメソッドの代わりにプロパティを使用できます。

public interface IAthlete 
{ 
    string Name { get; } 
    string Sport { get; } 
} 

自動プロパティでは、プロパティのバックストアを生成するようにコンパイラに要求できます。また、名前とスポーツのプロパティの実装を保持する基本クラスのPlayerを作成することを検討してください。

public class Player : IAthlete 
{ 
    public Player(string name, string sport) 
    { 
     Name = name; 
     Sport = sport; 
    } 

    public string Name { get; private set; } 
    public string Sport { get; private set; }   
} 

プレイヤーを実装するときに、基本クラスのコンストラクターに値を渡すことができます。そして、あなたのカスタムプレイヤーは、それらの機能のために特定のものだけを保持します(コードの重複はありません)。また、文字列を連結する代わりに、文字列形式を使用することをお勧めします。

public class BasketballPlayer : Player 
{ 
    public BasketballPlayer(string name) 
     : base(name, "Basketball") 
    { 
    } 

    public void Run(int distance) 
    { 
     Console.WriteLine("{0} just ran {1} meters.", Name, distance); 
    } 

    public bool Shoot() 
    { 
     Console.WriteLine("Successful shot for " + Name); 
     return true; 
    } 
} 

今すぐチームについて。 BasketballTeamにFootballPlayersを持っていない場合は、パラメータ化されたチームを作成する必要があります。また、IEnumerableを使用することを検討してください:

public interface ITeam<TPlayer> 
    where TPlayer : IAthlete 
{ 
    void AddPlayer(TPlayer player); 
    IEnumerable<TPlayer> Players { get; } 
    string Name { get; } 
    int NumberOfPlayers { get; } 
} 

また、共通の機能のために、基本クラスを作成することができます。新しいプレーヤーを追加する前に、現在チームにいるプレイヤーの数を確認する必要があります。

public class Team<TPlayer> : ITeam<TPlayer> 
    where TPlayer : IAthlete 
{ 
    private readonly List<TPlayer> _players = new List<TPlayer>(); 

    public Team(string name, int teamSize) 
    { 
     Name = name; 
     TeamSize = teamSize;    
    } 

    public void AddPlayer(TPlayer player) 
    { 
     if (_players.Count == TeamSize) 
      throw new Exception("Players number exceeded"); 

     _players.Add(player); 
    } 

    public string Name { get; private set; } 
    public int TeamSize { get; private set; } 

    public IEnumerable<TPlayer> Players 
    { 
     get { return _players; } 
    } 

    public int NumberOfPlayers 
    { 
     get { return _players.Count; } 
    }  
} 

カスタムチームの実装は本当に簡単になります。あなたは持っているプレイヤーのタイプを伝え、基本チームの実装チーム名とチームのサイズに渡します。

public class BasketballTeam : Team<BasketballPlayer> 
{ 
    public BasketballTeam(string name) 
     : base(name, 10) 
    { 
    } 
} 

今、あなたのプログラムが魔法のように動作:

class Program 
{ 
    static void Main(string[] args) 
    { 
     BasketballTeam bt = new BasketballTeam("MyTeam"); 
     BasketballPlayer bp = new BasketballPlayer("Bob"); 

     bt.AddPlayer(bp); 

     foreach (BasketballPlayer player in bt.Players) 
     { 
      Console.WriteLine(player.Name); 
     } 

     foreach (IAthlete a in bt.Players) 
     { 
      Console.WriteLine(a.Name); 
     } 
    } 
} 
+0

すべてのヒントをいただきありがとうございます。 – arkazeminia

3

Liskov Substitution Principleに違反しようとしています。そのようなHockeyPlayer –の追加などスーパータイプ–で行うことができる

ものはBasketballTeam含むサブタイプ–ともを行うことができます。

代わりに、あなたが使用する必要があるジェネリック:あなたのインターフェースは様々なゲームで使用されることを意図している場合

class Team<TPlayer> where TPlayer : IAthlete { 
    public ReadOnlyCollection<TPlayer> Players { get; } 
    public string Name { get; } 
    public void AddPlayer(TPlayer player); 
} 
+0

ここで欠けている概念はゲームです。 – Aliostad

+0

ありがとうございました。あなたが言っているまで、おかげでLSPは本当に考えられませんでしたが、私はあなたのコードを手に入れませんでした。私は一種の初心者です。 – arkazeminia

0

あなたがここにをゲームを逃すと、おそらくジェネリックを使用する必要があるようです:

public interface IGame 
{ 
    string Name {get;} 
    ... 
} 

public class Bastketball : IGame 
{ 
    ... 
} 

public interface ITeam<TGame> where TGame: class, IGame 
{ 
    void AddPlayer(IPlayr<TGame> player); 
    ... 
} 


public interface IPlayer<TGame> where TGame: class, IGame 
{ 
    ... 

} 

これは、バスケットボールチームに追加するホッケー選手から防ぐことができます。

0

SLaksが正しいです。あなたはすべての選手を受け入れないためにあなたのITeamに汎用的な制約を追加、ちょうどそれらのいずれかのタイプの可能性:

public interface ITeam<T> where T : IAthlete 
{ 
    void AddPlayer(T player); 
    IAthlete[] GetAthletes(); 
    // or: T[] GetAthletes(); 
    string GetName(); 
    int GetNumberOfPlayers(); 
} 

BasketballTeam実装は次のようになります。ここでは

public class BasketballTeam : ITeam<BasketballPlayer> 
{ 
    BasketballPlayer[] players; 
    // […] 

    public void AddPlayer(BasketballPlayer player) 
    { 
     this.players[this.numberOfPlayers] = player; 
     this.numberOfPlayers++; 
    } 

    public IAthlete[] GetAthletes() 
    { 
     return this.players; 
    } 

    // or: 
    // public BasketballPlayer[] GetAthletes() 
    // { 
    //  return this.players; 
    // } 

    // […] 
} 
+0

ありがとうございます。私は彼が言ったことを理解していませんでしたが、あなたが説明したことを得ました。これをクラス図にどのように表示するのですか? – arkazeminia

+0

@arkazeminiaこれは役に立ちますか? http://stackoverflow.com/a/860521/11963 – hangy

1

論理的には、

これらはあなたの基底クラスでなければなりません:BasketballTeam:チーム、選手

これらはあなたの派生クラスでなければなりません、BasketballPalyer

これらはPlayerのインターフェイスである必要があります:IPlay()、イルン、IGetNameなど。どちら

適用のように...

ガイドライン:動詞は、インターフェイス上でもっと良いスーツや名詞がクラスの良いスーツ。コード内のClassのための要件に最も適した名詞。

関連する問題