こんにちは、Reikaです。
私は現在、アプレンティスの5期生として日々勉強に励んでいます。
アプレンティスの課題としてオブジェクト指向の実装に取り組みました。
今回はこの経験を通じて学んだことについて、記述していきます。
今回のお題
早速ですが、今回は以下のトランプの戦争ゲームの実装を目指しました。
大まかなルール
・プレイヤーがカードを出し合い、カードの数の大小を比べる。
・強いカードを出したほうが勝ちとなり、相手のカードを含めカードをもらう。
・このようにして続けていき、誰かの手札がなくなったら終了。最後に多くカードを持っていた人が勝ちになる。
最初は要件を見て、めちゃめちゃ不安でした。コードのイメージが湧きませんでした。
ですが、今から記述するオブジェクト指向の三つの重要概念を押さえたら理解も早く済みました!
ではでは、私が学んだ知識をご説明します。
オブジェクト指向とは?
まずは、そもそもオブジェクト指向って何?というところから。
ざっくり言うと、全てを物(object)として考えて設計する方法です。
例えば今回のトランプゲームで言えば、プレイヤーとカードが物。
また、ゲームや判定のルールといった人や物以外の概念等も、物として考えます。
それらオブジェクト同士を関わらせることで1つの処理を作り上げることがオブジェクト指向です!
※この記事はオブジェクト指向の基本的用語は理解している上で記述しています。用語についてはこちらのサイトがとても分かりやすくておすすめです!
単一責任の原則
オブジェクト指向の中核をなす概念の一つに、単一責任の原則があります。
これは、名前の通り、一つのオブジェクトには一つの責任があるという考え方です。笑
具体的に説明します。
それぞれの物に関する処理を、クラスという設計図に分けます。
今回のゲームでは、以下のようにクラス分けしました。
クラス名 | 用途 |
---|---|
Mainクラス | ゲーム全体の実行 |
Cardクラス | カードに関する実行全て |
Playerクラス | Cardを継承してカードを引く |
Handクラス | 勝敗の判定全般 |
もちろん、全ての処理をMainクラスに書くこともできますが(オブジェクト指向を使わない書き方)、もしカードの枚数が増えたら?もしプレイヤーの人数が増えたら?
そんな時にスムーズに変更できるのがクラス分けの利点です。
はい。仕様変更があっても編集箇所は少なくて済むということが、オブジェクト指向の大きな利点であり、単一責任の原則なのです!
オブジェクト指向は、単一責任の原則をもとに、三つの重要概念が存在しています。
今から一つずつ説明して、さらにオブジェクト指向を自分のものに説明していきます!
継承
お待たせしました。ここからはオブジェクト指向の三代重要概念のお話しです。
まず一つ目、継承です。
早速ですが先ほど記載したクラスの表をご覧ください。
Playerクラスの用途の部分に注目です。
クラス名 | 用途 |
---|---|
Mainクラス | ゲーム全体の実行 |
Cardクラス | カードに関する実行全て |
Playerクラス | Cardを継承してカードを引く |
Handクラス | 勝敗の判定全般 |
この継承とは、クラスが他のクラスの持つメソッドを引き継ぐことです。
厳密に言えば、親クラスで定義した関数を、子クラスでも同じように使用することができる、と言うことです。
例えばCardクラスにある、シャッフルしたカードを得るgetCard()メソッドを記載していて、プレイヤーそれぞれにカードを配りたい時、同じようにPlayerクラスでもgetCard()メソッドを使用したいと考えます。
その時に使えるのが継承です。
書き方は以下の通りです。
class Card{
private array $playerCards;
public function getCard(){
return $this->playerCards;
}
}
class Player extends Card{
}
$saito = new Playe();
$saito->getCard();
ポリモーフィズム
次に、二つ目のポリモーフィズムについてです。
んー、難しい言葉。と思いましたがそれは第一印象だけ。日本語に訳すと多様性という言葉になります。
多様性。私が前のクールでめちゃ好きだったテレビドラマ「不適切にもほどがある!」のセリフでもよく出てきました。笑
話が逸れましたが、ポリモーフィズムとは、プログラムを記述する際に、同じ名前のメソッドや関数であっても、中身の違いによってそれぞれのオブジェクトに合わせた異なる動作をするというものです。
この考え方により、プログラムで同じ命令を実行しても、それぞれが独立した固有の処理を行うことが可能になりました。多様性感じる…!笑
例を挙げて説明しますね。私は現在、スクールでチーム開発をしています。チームメンバーは4人いますが、人間というものはコピーなんて存在しないので、みんなバラバラな挨拶をします。
そう、この例で例えるとポリモーフィズムとは、個々のメンバーが独自の挨拶をすると言うことです。
さらに、今後新しいメンバーが加わっても、挨拶をするという共通の処理はすでに書かれているので、新しいメンバーを加えるだけで済みます。つまり、学習カリキュラムがもう決まっているということです。
コードは以下の通りです。
class TeamMember {
protected $name;
public function __construct($name) {
$this->name = $name;
}
public function geetings() {
}
}
class Member1 extends TeamMember {
public function geetings() {
echo $this->name . ": お疲れ様でーす。\n";
}
}
class Member2 extends TeamMember {
public function geetings() {
echo $this->name . ": おはようございます。\n";
}
}
class Member3 extends TeamMember {
public function geetings() {
echo $this->name . ": ごめんなさい今日も寝坊しました。\n";
}
}
$tanaka = new Member3("Tanaka");
$tanaka->geetings();
こちらのコードの出力結果は、
Tanaka: ごめんなさい今日も寝坊しました。
です。(実際にそんなメンバーはいません。笑)
カプセル化
最後に三つ目、カプセル化です。
結構プログラミング用語って、言葉のそのままなことが多いな〜と、学んで感じました。今回もそんな感じです。
メソッドやプロパティなどは定義するときにアクセス権をつけます。
例えば今回のカードクラスを例に挙げて見ます。
class Card{
private array $cards;
//プロパティ
public function shuffleCard(){
//メソッド
shuffle($this->cards);
$this->player1Cards = array_slice($this->cards, 0, 26);
$this->player2Cards = array_slice($this->cards, 25);
}
}
それぞれメソッドとプロパティの頭にprivateとpublicという文字があります。
これがアクセス権であり、prvateがカプセル化したプロパティと言うことでございます。
アクセス修飾子 | アクセスできる範囲 |
---|---|
public | どこからでもアクセス可能 |
protected | そのクラス自身、継承したクラス、親クラスからのみアクセス可能 |
private | そのクラスからのみアクセス可能 |
まとめ
いかがでしたでしょうか?
自分が書いたコードも全て共有したいところですが、現時点では、とりあえず希望通りに動作する程度の、まだ整理されていないコードですので、、、
オブジェクト指向の理解が深まったら、改めてシェアしたいと考えています!笑
最後まで読んでくださり、ありがとうございました!