皆さんはオブジェクト指向という言葉をご存知ですか?
オブジェクト指向とは「モノやコトに着目すること」を指します。
また、そのオブジェクト指向を組み込んでシステム開発することを「オブジェクト指向プログラミング」と言います。
ここでは「オブジェクト指向って何?」「なんでオブジェクト指向でプログラミングするの?」「オブジェクト指向の使い方が知りたい」といった方へ、オブジェクト指向プログラミングについてご紹介します。
オブジェクト指向プログラミングとは
まずはオブジェクト指向プログラミングについて説明しましょう。
オブジェクト指向プログラミングは
- モノに着目する
- モノがどんな状態で、どんな動きをするのかを設計し、設計図を作る
- その設計図を沢山作ってプログラム内で使う
- そういったプログラミングの考え方(概念)
です。
プログラムを作る上で必要な部品の設計図を一つずつ作って使うというイメージです。
オブジェクト指向でサイコロの機能を実装する
では実際にオブジェクト指向プログラミングをしてみましょう。
今回はサイコロという「モノ」に着目してプログラミングし、サイコロを3回ふった合計値を出力するプログラムを作ってみましょう。
プログラムのイメージはこんな感じです。
count = 0
for i in range(3):
サイコロをふる
count += サイコロの出目
print(f"合計:{count}")
サイコロをふり、出たサイコロの数字をcount変数に加算していき、最後にprintで出力します。
このプログラムで使うサイコロを設計していきましょう。
もしサイコロが近くにあったら、サイコロを横に置きながら読み進めるとより実装しやすいかと思います。
サイコロの設計図を作り、それをプログラム内で使えるようにするためには、まずサイコロの特徴や状態、そしてどんな動きをするのかを正確に抽出する必要があります。
まず特徴と状態からみていきましょう。
特徴・状態
- 正六面体
- 白い
- 1は赤色
- 他の色は黒色
- そこそこ硬い素材
- 軽い
- 最初の出目は1
- 4と5が見えてる
他にもあると思いますが、このくらいにしておきましょう。
次にサイコロがどんな動作をするか、サイコロを使ってどんなことができるのかを考えてみましょう。
動作
- ふると出目が変わる
- サイコロを積み上げられる
シンプルなモノだから、できることは少なめですね。
この中から作りたいプログラムに必要そうな特徴や状態、動作を抽出します。今回作成したいプログラムは出目がわかれば問題なさそうなので
特徴・状態
- 最初の出目は1
動作
- ふると出目が変わる
これだけで良さそうです。
このように、実物のサイコロから必要な機能や特徴のみを抽出することを「抽象化」と言います(反対に抽象的なものを実物にすることを「具体化」と言います)。
では抽象化したサイコロを設計図に落とし込んでみましょう。
[dice.py]
import random
class Dice:
number = 1
def roll(self):
self.number = random.randint(1, 6)
dice.pyファイルを作成して設計しました。
イメージはこんな感じです。
では上から順に見ていきましょう。
まずサイコロの機能に必要なrandomモジュールを読み込んでいます。randomモジュールのrandint()を使ってサイコロの出目をランダムで取得します。
次にclass Diceで「クラス」というものを作成しています。このクラスが設計図そのもので、この中にサイコロの状態や動作を盛り込んでいきます。
まずは状態から考えていきましょう。状態のところで抽出した「最初の出目は1」は、プログラミング的には「数値の1を保持した変数」があれば大丈夫そうです。
なので、number変数を用意し、1を代入しています。
このnumberのことを、クラスの中にある状態を表す変数なので「クラス変数」と呼びます。
次にサイコロの動作を設計していきましょう。動作はメソッドで表します。メソッドとはクラス内の関数の呼び方です。
roll()がサイコロをふるメソッドです。selfという引数を持っていますが、これは自分自身を表す引数です。
Pythonでは自分が所属するクラスを表すためにselfを使います。self.numberとすることで、先ほど定義したnumberクラス変数にアクセスできます。
roll()したらrandint()を使って1〜6の整数をランダムに取得し、number変数に格納しています。
これで完成です。次にmain.pyにサイコロを3回ふった合計値を出力するプログラムを記述します。
[main.py]
from dice import Dice
dice = Dice()
count = 0
for i in range(3):
dice.roll()
print(f"{i+1}回目:{dice.number}")
count += dice.number
print(f"合計:{count}")
[出力結果]
1回目:5
2回目:5
3回目:3
合計:13
randintを使っているので結果は実行ごとに変わります。
まず先ほど設計したDiceクラスをインポートしています。ファイル名がdice.pyなので、from dice import DiceでDiceクラスをインポートします。
次にインポートしたDiceをdice変数に格納します。クラスを呼び出すときにクラスは初期化され「インスタンス」になります。
インスタンスは「設計図を元に作った製品」のようなイメージです。そのインスタンスを格納した変数のことを「インスタンス変数」と呼びます。
インスタンスを生成したら、次にfor..inで3回ループさせ、dice.roll()でサイコロをふり、出た結果をdice.numberにアクセスして計算します。
最後に3回分のdice.numberの値を出力しています。
クラスの最も基本的な使い方は以上ですが、実はインスタンスを通して直接クラス変数(クラス内のnumber変数)にアクセスするのは、オブジェクト指向プログラミングの原則に違反しています。
その点を踏まえ、後編では「カプセル化」と「継承」について学習していきましょう。