オブジェクト指向の考え方 竹内 亮太 はじめに この資料は、オブジェクト指向プログラミ ングの理解を補助するためのものです 世の中には「オブジェクト指向とは何か」を 説いた書籍や資料は多いですが、オブジェクト 指向への移行の仕方や、その具体的な意味や 意義について述べたものは少ないのが実情です なので、作ってみました 前提知識 プログラミング演習の内容は大前提です 変数とは何か 配列とは何か メソッドとは何か 引数や返値までしっかり復習すること その他、条件分岐や繰り返しの構文 Java言語に限定した内容ではありません C++言語などにも応用できます 理解のフェイズ オブジェクト指向は、フェイズ(段階)に 分けて理解していくことをおすすめします 自分に理解できて応用できそうな要素を、 段階を踏んで導入していけばよいでしょう 一度理解したフェイズも、時間をおいて 復習してみましょう 理解の質が変わってくるはずです 変数のおさらい 値を覚えておくための箱のようなもの 1つの箱に1つだけ、値を入れておける 入れる値の種類に応じて、違う型を使う 整数なら int 型、実数なら double 型など int iA = 12; 12 int型 iA 変数の限界 変数1つには、1つの値しか入れられない だが実際には、1つの数値だけでは表しきれ ない物事が多数存在する 例:RPGのキャラクターステータス 名前、職業、レベル、HP、MP、力、素早さ、 etc… 例:三角形や長方形などの図形情報 幅と高さ、のように複数の値でないと表現不可 キャラクターを表現してみよう 右のようなステータス 画面のゲームの場合 String sName = “剣士子”; String sClass = “Swordman”; int iLevel = 4; int iExp = 0; int iNowHP = 150; int iMaxHP = 150; int iStr = 31, iVit = 28; int iDex = 14, iAgl = 11; int iInt = 7, iWis = 10; だいたいこんな感じで できています 剣士子 Swordman キャラクターは1人じゃない さっきのゲームが4人 パーティでプレイする ゲームだったとする あと3人分も、あんな 感じで変数を用意する のか? …やってらんねぇ! String charaB_sName = “エルフっ娘”; String charaB_sClass = “Archer”; int charaB_iLevel = 54; int charaB_iExp = 65535; int charaB_iNowHP = 420; int charaB_iMaxHP = 420; int charaB_iStr = 123, charaB_iVit = 119; int charaB_iDex = 241, charaB_iAgl = 180; int charaB_iInt = 176, charaB_iWis = 155; ↑これがあと2キャラ分必要になる 「クラス」の誕生 複数の値で何か1つの対象を表す時に、 その値をまとめておきたい まとめた上で、そのまとまったものを 「1つの変数として」扱えたら便利かも? じゃあ必要な変数をまとめたものを 「クラス」と呼ぶことにしよう 作ったクラスは int や double みたいに、 「変数の型の1種類」として 扱えることにしよう クラスの作り方 だいたい授業で説明したとおり public class Character { public String sName; public String sClass; public int iLevel, iExp; public int iNowHP, iMaxHP; public int iStr, iVit, iDex, iAgl, iInt, iWis; } この段階では、まだ 「新しい型の変数の箱」を 設計した(デザインした)だけにすぎない クラスの使い方 「クラス型変数」には、自分で決めた「メンバ変 数」の分だけ、別々に値をしまうことができる こうやって使う Character charaA = new Character(); charaA.sName = “剣士子”; 以下のようなイメージ(一部メンバ変数だけ抜粋) String型 String型 int型 sName sClass iLv Character型 charaA int型 iHP int型 iStr 量産しよう、そうしよう 一回作ったクラスは、 いくらでも量産して 使い回しが可能 String型 sName String型 int型 int型 int型 sClass iLv iHP iStr Character型 Character charaB = new Character(); Character charaC = new Character(); Character charaD = new Character(); 変数1つでキャラクタ ー1人を表せている charaB String型 sName String型 int型 int型 int型 sClass iLv iHP iStr Character型 charaC String型 sName String型 int型 int型 int型 sClass iLv iHP iStr Character型 charaD フェイズ1:クラスとは 何かを表すための値の集まり 値の集まりを、1つの変数のように扱える クラスを作るということは、オリジナルの変数 の箱をデザインするようなもの 作ったクラスを利用する時は、 クラス名 変数名 = new クラス名(); として、クラス型変数を宣言して利用する こうして作ったクラス型変数を 「インスタンス」と呼ぶ インスタンスを作ることを「実体化」とも言う 値をまとめたその次は 例:キャラクターのレベルアップ処理 charaA.iLevel++; charaA.iMaxHP+=20; charaA.iStr+=5; … いちいち「charaA.~」とするのは面倒 charaBに対しても同じように書かなくては ならないなら、値をまとめた意味が薄くなる 値をまとめたら、それに関する処理も まとめたくなってくる むしろまとめるべき メソッド化しよう クラスのメンバに関する処理は、 可能な限りメソッド化する レベルアップ処理のメソッド public void incremntLevel() { iLevel++; iMaxHP+=20; iStr+=5; … } 呼び出し側からの呼び出し charaA.incremntLevel(); charaB.incremntLevel(); // charaA がレベルアップ // charaB がレベルアップ メソッド化のメリット 同じような処理を何度も書かずに済む お決まりの手続きを1回の呼び出しで済ませる 複数のオブジェクトに対しても、呼び出し一発 メンバ変数を好き勝手にいじらせない メソッドの中で値をチェックすることで、 入れて欲しくない値を弾くことができる HPがマイナスになったらまずい、などなど 直接操作と間接操作 例:ダメージを与える処理 HPが20の時に、50のダメージが当たった メソッドを使わない場合 charaA.iNowHP-=50; // 現在HPが-30になる メソッド化した場合 public void damage(int argDmg) { iNowHP-=argDmg; if(iNowHP < 0) { iNowHP = 0; } } ~~(↑はクラスの内部・↓は呼び出し側)~~ charaA.damage(50); // マイナスになる心配がなくなる! アクセス制御 せっかくメソッドを用意しても、どこかで 直接値をいじられたら意味がない クラスの外からいじれるもの、いじって 欲しくないものを分ける必要が出てくる 外からいじってもいいメンバには public を型の前につける 外からいじられたくないメンバには private を型の前につける 全部 public じゃダメなん? ダメです 小規模なプログラムでは問題ないですが、 好き勝手にいじれる状態にしておくと、 後々混乱の原因になります 基本的に変数は private にしておく 各変数に対しては、値をセットしたり返してく れたりするメソッドを public で用意しておく メンバ変数を読み書きするためのメソッドを、 setter や getter と呼ぶ いちいち set したり get したり 面倒ですよね 本来ならば、間に値をチェックしたりする必要 がなければ、直接代入したり参照しても構いま せん(クラスの利用目的にもよります) ですが、今は練習がてらアクセッサ(setter & getter)を作る作業をして、慣れてください 特別なメソッド:コンストラクタ クラス型変数を new するのと同時に、 入れておきたい値、しておきたい処理を 書いておくメソッド クラスと同じ名前のメソッドを作ると、 それがコンストラクタになる キャラクターなら、レベル1のステータスを 入れておきたい、など 返値の型は指定しない コンストラクタは引数を取れる 引数を付けたら、new する時に引数を渡す必要 がある コンストラクタの例 キャラクターを作る時に、名前と職業だけ 決めて、後のメンバ変数にはレベル1の ステータスをセットしたい // コンストラクタの作成例 public Character(String argName, String argClass) { sName = argName; sClass = argClass; iLevel = 1; … } ~~(↑はクラスの内部・↓は呼び出し側)~~ // new する側はこんな感じ Character charaA = new Character(“エルフたん”, “Archer”); フェイズ2:メソッドとアクセス制御 クラスのメンバ変数に対する処理をまとめ たものを、メソッドと呼ぶ メンバ変数へのアクセスはメソッドを 通じて行い、直接いじったりはしない メンバ変数とメソッドを持つことで、 クラスの本来の意義が完成する それを徹底させるため、public や private など のキーワードを指定し、アクセスを制御する new するついでに色々やらせることが可能 コンストラクタ 次のフェイズに向けて 次のフェイズはちょっと次元跳躍します これまでの内容でも、オブジェクト指向の メリットは大きいはずです 十分プログラムの書き方は効率的になってます ですが、これからが真骨頂です しっかり復習してから進みましょう 色んなものをクラスで表そう 例:図形 三角形 長方形 円 直方体 球 円錐 … 例:RPGのキャラクター 戦士 ナイト 僧侶 魔法使い ハンター 盗賊 アサシン 司祭 賢者 パラディン … 共通点があるもの多いよね? 図形は全て「図形」という括りにできる 更に言うなら平面図形と立体図形に分けられる 職業も、全て「キャラクター」で括れる 更に言うなら、各職業には「上位」のものが あったりする ナイト→パラディン 僧侶→司祭 魔法使い→賢者 もっとクラス化を効率よく 考え方その1 共通点だけを括りだしてクラスにする それに個別のメンバを足して、「継承」したクラスを 作る 例:「図形」という抽象的なクラス 例:「三角形・直方体」などの具体的なクラス 考え方その2 基本的な機能(能力)だけを持ったクラス 例:「ナイト・僧侶・魔法使い」など それを「継承」し、追加機能(能力)を持たせたクラス 例:「パラディン・司祭・賢者」など 表現する物事を体系化する 図形 平面図形 長方形 三角形 円 立体図形 直方体 円錐 球 キャラクター ナイト 僧侶 賢者 ハンター 司祭 魔法使い パラディン レンジャー シーフ アサシン 「継承」のメリット 共通部分をわざわざ書かなくてよい 付け加えたり、置き換えたい部分だけ作る 変数の追加 メソッドの追加 メソッドの置き換え こういうことができる↓ 継承元クラス 変数名 = new 継承先クラス(); 図形 shape = new 長方形(); ナイト chara0 = new パラディン(); 子は親の一種として扱うことができる 続きは本編で 本編の深度に応じて続きも書きます
© Copyright 2024 ExpyDoc