「オブジェクト指向について、調べてみたけど難しい用語ばかりで理解できない」
「なぜオブジェクト指向が必要なのか?」
とプログラミング学習をしている方の多くが感じていると思います。
多くの参考書や解説記事では用語の説明ばかりで、オブジェクト指向でコードを書く理由について触れられていない場合が多いです。
そこで今回はプログラミング初心者でもオブジェクト指向を理解できるように、RPGゲームを例にしてわかりやすく解説しました。
オブジェクト指向とは
まずオブジェクトとオブジェクト指向について、簡単に説明しておきます。
[オブジェクトとは?]
人間がプログラミングしやすいように、作ったモノ。
クラスやインスタンスなどが、オブジェクトに当たります。
[オブジェクト指向とは?]
オブジェクトを作って、変更に対して対応しやすいようにコードを書くこと。
RubyやPythonなど多くのプログラミング言語で採用されています。
オブジェクト指向のメリット
ここからはオブジェクト指向で、プログラミングするメリットについて解説していきます。
オブジェクト指向を使う最大のメリットは、変更に対応しやすいようにプログラミングできるところです。
例えば、皆さんがRPGゲームの開発者だとします。魔法使いや勇者などの主人公が、モンスターと闘うゲームを想像してください。
まず皆さんは、主人公の設定や行動パターンを定義しなければいけません。
そこでこのように、1つずつプログラミングしていったとします。
▶︎魔法使いの攻撃力は、30である。
▶︎魔法使いは、◯ボタンを押すと攻撃する。
▶︎魔法使いは、△ボタンを押すと防御する。
▶︎勇者の攻撃力は、60である。
▶︎勇者は、◯ボタンを押すと攻撃する。
▶︎勇者は、△ボタンを押すと防御する。
しかし社内のミーティングで、このように仕様を変更することになりました。
▶︎「◯ボタンを押すと防御する」
▶︎「△ボタンを押すと攻撃する」
そのため、これまで書いてきたコードを下記のように1つずつ修正していくことにしました。
▶︎魔法使いの攻撃力は、30である。
▶︎魔法使いは、△ボタンを押すと攻撃する。
▶︎魔法使いは、◯ボタンを押すと防御する。
▶︎勇者の攻撃力は、60である。
▶︎勇者は、△ボタンを押すと攻撃する。
▶︎勇者は、◯ボタンを押すと防御する。
今回は主人公が2人だったので、変更に時間はかかりませんでしたが、主人公が100人になった場合はどうでしょうか?
先程と同じように仕様変更が起きた場合、変更するのに多大な時間や労力がかかり非効率です。またミスも起きやすくなり、バグの原因にもなります。
ここで登場するのが、「オブジェクト指向」という考え方です。
勇者も魔法使いも人間の一部なので、共通する設定は「人間」というオブジェクトにまとめておきます。また主人公のタイプによって異なる部分は、「勇者」や「魔法使い」などのオブジェクトに分けてプログラムを書いていきます。
[人間]
・△ボタンを押すと攻撃する
・◯ボタンを押すと防御する
・攻撃力という設定を持つ
・勇者などのタイプを持つ
[勇者]
・攻撃力は「60」
・タイプは「勇者」
[魔法使い]
・攻撃力は「30」
・タイプは「魔法使い」
このようにしておけば、「△ボタンを押すと防御するように変えたい」と要望があっても、プログラムをオブジェクトで書いておけば「人間」のコードを書き換えるだけで済みます。
変更に対応しやすいことこそがオブジェクト指向の最大のメリットです。
次にオブジェクト指向を理解する際に重要な用語について,
「勇者」と「魔法使い」の例を用いて解説していきます。
用語① クラス
同じ特徴や性質を持つモノをまとめたオブジェクト。先程の例で言う「人間」がクラスに当たります。クラスは、インスタンスを作るための設計図です。
Rubyでクラスを定義する際は、下記のようにコードを書きます。またクラス名は必ず大文字から始める必要があります。
class クラス名
用語② プロパティ
オブジェクトが持っている特徴を言います。「攻撃力」や「タイプ」などがプロパティに当たります。
用語③ メソッド
オブジェクトが起こすアクションのことを言います。
「△を押すと、攻撃する」「◯を押すと、防御する」がメソッドに当たります。
Rubyでは、関数を用いてメソッドを表現する場合が多いです。
def メソッド名
処理
end
用語④ インスタンス
クラスによって、作られたオブジェクトです。今回の場合、「人間」クラスによって作られた「勇者」と「魔法使い」がインスタンスに当たります。
Rubyでインスタンスを生成する際は、下記のように書きます。
インスタンス名 = クラス名.new
オブジェクト指向の3大要素
次にオブジェクト指向の3大要素について解説していきます。
オブジェクト指向には、「継承」「カプセル化」「ポリモーフィズム」の3つの特徴があります。
この特徴を学ぶことで、RubyやPythonなどオブジェクト指向の言語を理解しやすくなるので、頑張りましょう。
オブジェクト指向の特徴① 「継承」
オブジェクト指向の1つ目の特徴は「継承」です。継承とは、「共通する部分を受け継ぐこと」を指します。
継承するメリットは、クラスが複数ある時に、同じコードを何度も書く必要がなくなることです。では継承について、RPGゲームを例に解説していきます。
先程、皆さんは勇者や魔法使いなどを作りました。新たに「ドラゴン」を仲間に加えて、ゲームで操作できるようにしたいとします。
ドラゴンの設定は下記のようにしました。
▶︎[ドラゴン]クラス
--「人間」クラスと共通する部分--
- △ボタンを押すと攻撃する
- ◯ボタンを押すと防御する
- 「タイプ」や「攻撃力」などの設定を持つ
--「人間」クラスと異なる部分--
これらを図にすると下図のようになります。
ドラゴンクラスも、「Xボタンで休憩」という行動以外は、同じプロパティとメソッドを持つのが分かります。
ここで人間クラスとドラゴンクラスを内包するように、キャラクタークラスを作ります。
図で表すと、下図のようになります。
では、人間とドラゴンクラスの設定をゲームに反映させるためにはどうすれば良いでしょうか?下記のように何度もコーディングする必要はありません。
- △ボタンを押すと攻撃する
- ◯ボタンを押すと防御する
- 攻撃力という設定を持つ
- 勇者などのタイプを持つ
なぜなら人間クラスとドラゴンクラスは、キャラクタークラスを継承させることで、変数や行動などの共通部分のコードは省略することができるからです。そのため「Xボタンを押すと休む」のような異なる特徴の部分のみ、コードを書いて定義するだけで済みます。
Rubyではクラスを継承する場合、下記のように書きます。
class Ningen < Character
(省略)
end
class Dragon < Character
(省略)
end
継承されるクラスを「親クラス」、継承するクラスを「小クラス」と呼びます。
継承を使うことで、効率的に開発を進めることができ、またミスを防ぐことができます。
オブジェクト指向の特徴② 「カプセル化」
2つ目の特徴が「カプセル化」です。
カプセル化とは、オブジェクトが持つプロパティ(属性)などの情報を外部から直接書き換えられないように隠した状態を言います。
RPGゲームの例に戻って、解説していきましょう。
人間クラスは、相手を倒すと攻撃力が「5」上がる設定にしました。攻撃力の初期設定は「30」としています。
power = 35のように直接データを書き換えるのは、不具合の原因に繋がるので良くないとされています。
<カプセル化されていない状態>
class Ningen
attr_accessor :power
#初期状態を定義
def initialize
self.power = 30
end
(途中省略)
end
#データを直接書き換え
power = 35
次にカプセルされた状態のコードを見てみましょう。
<カプセル化された状態>
class Ningen
attr_accessor :power
def initialize
self.power = 30
end
#関数を使ってデータを書き換え
def levelup
power = power + 5
end
(途中省略)
end
powerの値を直接書き換えるのではなく、「levelup」という関数を使って定義しています。
つまりこの関数を呼び出さないと、powerの値は変更されません。
これによって、powerの値を消したり、誤って書き換えてしまうミスも防ぎます。また、後から「相手を倒すと攻撃力が10上がる」としたい場合、下記のように書き換えれば良いだけです。
def levelup
power = power + 10
end
カプセル化のメリットは、下記2点です。
・不具合を防ぐ
・後からカスタマイズしやすい
オブジェクト指向の特徴③ 「ポリモーフィズム」
最後の特徴が「ポリモーフィズム」です。日本語で「多態性」とも表現されます。
ポリモーフィズムとは、同じ命令をしても、クラスによって行動が異なることを指します。
これだけだと少し分かりにくいので、キャラクタークラスを使って解説していきます。
キャラクタークラスの行動の中に、挨拶機能を加えてみます。
ここで人間とドラゴンに対して、挨拶メソッドを実行してみます。そうすると下記のような反応が得られました。
人間:「やあ!」
ドラゴン:「ガオオ!」
このように同じメソッドを実行したにも関わらず、返答の内容が異なっているのが分かります。これが「ポリモーフィズム」の特徴です。
もう少しポリモーフィズムについて、理解するためにRubyのコードで解説していきます。
#Characterクラス(=親)を定義
class Character
attr_accessor :name
def hello(voice=''”)
"#{self.name}: #{voice}"
end
end
#Ningenクラス(=子)
class Ningen < Character
def hello(voice=''やあ!”)
super
end
end
#Dragonクラス(=子)
class Dragon < Character
def hello (voice=”ガオオ!”)
super
end
end
#ningenというインスタンスを生成
ningen = Ningen.new
ningen.name = '人間'
#dragonというインスタンスを生成
dragon = Dragon.new
dragon.name = 'ドラゴン'
#helloメソッドを実行
ningen.hello 実行結果=>人間: やあ!
dragon.hello 実行結果=>ドラゴン:ガオオ!
NingenもDragonクラスも同じ「hello」メソッドを実行しているので、実行結果が異なります。
ここまでオブジェクト指向の特徴やメリットについて解説してきました。
重要なのは、「効率的かつ不具合が出ないようにコードを書くためにオブジェクト指向を使う」という点です。
クラスやインスタンスなど、なぜ「オブジェクト」という概念があるのか理解できれば、今後のプログラミング学習をより効率的に進められます。
最後に本記事の内容をまとめておきましたので、ぜひ参考にしてみてください!
[1]オブジェクト指向とは、変更に対応しやすいようにコードを書くこと
[2]継承とは、共通する部分を受け継ぐことができるようにすること
[3]カプセル化とは、外部からデータを直接書き換えることができないようにすること
[4]ポリモーフィズムとは、同じ命令でもクラスによって、異なった行動をすること