質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.55%

【カードゲーム】カードを引く(or配る)メソッドはどこに実装すべきか。

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 8,898

Jake

score 275

はじめまして、java教材向けに簡単なカードゲームを制作しました。制作後、もうすこしリファクタリング&拡張性のあるコードにできないものかと思い、この場を借りて質問させて頂くことにしました。

ざっとですが、下のようなクラスがあります。

  • Cardクラス(カード)
    -カードの数値
    -カードのスート(ダイヤ、スペードなど)
    -カードの表示値 (数値は1でも表示はAなど)
  • Deckクラス(カードの山)
    -Card[52](一山分)
    -shuffle() カードをシャッフル
  • Playerクラス (プレイヤー)
    -Card[](手札分)
    -cardCount (手持ちカード枚数)
    -addCound()(手持ちカード枚数カウンタを増やす)
  • Gameクラス (ベースクラス:main()があります)
    -Deck mainDeck (カードの山)
    -cardMax (現在の山の枚数)
    -hitCard() (カードを引く)

【カードを引く】というメソッドは、main()のあるGameクラス内に記載し、ゲームループから呼び出しました。

static void hitCard(Player p) {
    //山の一番最後からカードを一枚取って、プレイヤーのカード配列に入れる
    p.cards[p.cardCount]=mainDeck.cards[cardMax - 1];
    //手持ちカード枚数カウンタを増やす
    p.addCount();
    //山の枚数を減らす
    cardMax--; 
}
と、こんな感じです。
上記コード&記載場所で動作的には何ら問題はないです。

ここからが質問なのですが、Gameクラスに【カードを引く】というメソッドを書くのはどうなんでしょう?

例えば、複数のカードゲームを選択してプレイできるように今後プロジェクトを改造する場合を想定したら、【カードを引く】メソッドはどこに実装すべきだと思いますか?

今考えているのは、Gameクラスをmain()持ちではないクラスに変更し、各ゲームはGameクラスを継承した物にするという作りに。スーパークラスのGameクラスの中に【カードを引く】メソッドを実装するのが妥当なのかな?と考えています。

皆さんの思考をお聞かせ頂きたいです。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

僕はオブジェクト指向を使う主な目的は、コードの書き方を現実世界の表現に近づけるためのモノと考えています。(DDDで言うユビキタス言語です)そういう意味で、Gameカードを引くメソッドを持っているとゲームがカードを引くとコード上は表現されます。コード上現実世界を表現できていますか?これをコードにすると

// ゲームはプレイヤーのためにカードを引く(Game hits card for player)
game.hitCard(player);

と表現されるはずです。

これよりは、カードを引くプレイヤーがカードを引くの方がそれっぽいですよね。現実世界でカードを引くのはプレイヤーですから。Gameにはカードを配るメソッドが定義されており、そこでカードの配り方が定義されていたら下記のように実装されるでしょう。

public class Game {

  public void deal(){
    Card card = drawFromDeck();
    player.hand(card); // Gameがカードを配る
  }

  private Card drawFromDeck() {
    // デッキからカードを選ぶ実装例
    return deck.cards[random];
  }

}

ところで、プレイヤーに配るカードは、カードゲームのルール毎に異なりませんか?例えばポーカーと七並べのルールで遊べたとして、1枚ずつ配るのか、数枚まとめて配るのか、はカードゲームのルールに定義します。Gameにカードを配るを実装するよりも、Ruleにカードを配るを実装した方がそれらしくなります。

こうしていくことで、コードにドメインの知識を語らせる事ができるでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/18 12:11

    コメントありがとうございます。

    書かれている通り、「Gameがカードを引く(配る)」というカタチになっている、というのも懸念点の1つでした。

    まとめて配る場合や順に配る場合といろいろパターンがありますが、基本的には1枚ずつ配ることの繰り返しですので、仮想ゲームマスターに配ってもらう、という感覚で作っていたのですが、書かれている内容を見ると、方向性がクリアになってきたような気がします。

    ありがとうございます。

    キャンセル

  • 2015/08/18 13:46

    GameMasterは良いクラス名ですね。Ruleがカードを配るのもあとになって変な気がしました。GameMasterがRuleを知っていて、そのRuleに合わせてカードを配るんですね。

    キャンセル

0

質問に対するリファクタリングを考えてみました。
1-Gameクラスを抽象クラス化
2-抽象メソッドdoTurnを追加→ゲーム内の状態を変化させるメソッド、今回のカードを引く等の行為など
3-抽象メソッドjudgeを追加→ゲーム状態変化に伴う勝敗判定
4-Gameクラスのmain内で2.3を呼ぶ
5-Gameを実装したCardGameを実装

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/18 12:13

    コメントありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.55%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる