【具体例あり】オブジェクト指向プログラミングとは?プログラミングスタイルを中心に分かりやすく解説
オブジェクト指向プログラミングという言葉は、ITエンジニアとして勉強したことがある人なら、誰しも聞いたことがあるのではないでしょうか。
しかし、このオブジェクト指向プログラミングが、
・他のプログラミングとどう違うのか
・どんな特徴があるのか
・どう勉強すれば良いのか
について迷う人は多いでしょう。
今回の記事では、
「オブジェクト指向プログラミングとは何か」
「今までのプログラミングとはどのように違うのか」
「オブジェクト指向のプログラミングスタイル」
について解説します。
「プログラミングスタイル」は事例に基づいて具体的に解説することで、「オブジェクト指向プログラミングは難しい」という悩みを解消するように努めました。
オブジェクト指向プログラミングとは
オブジェクト指向ブログラミングでいう『オブジェクト』とはソフトウェア部品のことで、
・一つひとつのオブジェクトは独立して存在し、それぞれ固有の役割・責務を持っている
・互いにメッセージを通じて協調動作をしながら全体として1つの仕事をする
ものです。
オブジェクト指向プログラミングは、従来から多く採られている手続き型プログラミングに比べて、
「プログラムを効率よく作ることができる」
「不具合が起きたときに対処しやすい」
「プログラムに変更を加えやすい」
など多くのメリットがあります。
手続き型とオブジェクト指向の比較
「オブジェクト指向」を理解するには、「手続き型」と比較するのが分かり易いです。
その違いをクリアにするために、
「日常生活で数人のグループで何かの作業を始める際に、リーダーの指示の出し方」
を用いて説明します。
・オブジェクト指向では、リーダーは「何をするかレベルの大まかな指示」を出し、詳細はメンバーに任せる
・手続き型では、リーダーは「何をどのようにするかまでブレイクダウンした細かな指示」を出してメンバーを手足の如く扱う
という違いがあります。
前者の場合は指示を理解して実行できるスキルを持っていることがメンバーに求められ、後者の場合にはこのようなスキルは求められません。
手続き型プログラミングでは、何をどのようにするかまで指示します。
このような細かな指示をするために、main文が
「グローバル変数」
「関数」
「条件分岐」
「繰り返し文」
などを全て把握しなければならず、情報量が多くコードが複雑になり、柔軟性や可読性を下げることになります。
オブジェクト指向プログラミングでは、オブジェクトと呼ばれる構成単位の組み合わせとしてシステム全体を捉えるもので、システム全体の振る舞いはオブジェクト間の相互作用
(機能を呼び出して処理を依頼)
として記述されます。
つまり、
・何をインプットするのか(引数)
・何がアウトプットされるのか(返り値)
が重要視され、その過程はブラックボックスになっているのです。
オブジェクトとはこのような能力を持つものです。
なぜオブジェクト指向プログラミングをする必要があるのか?
オブジェクト指向でプログラミングする大きな目的は、
「変更に柔軟に対応するため」
です。
システムは将来的に変更がし易いように開発する必要がありますが、システムには「頻繁に変更される個所」と「余り変更されない箇所」があります。
システムが変更しやすいように、システム全体に柔軟性を持たせようとするとコードが複雑になり、却ってメンテナンスし難いものになってしまう恐れがあります。
そこで、オブジェクト指向プログラミングでは
「頻繁に変更される個所や変更内容を特定する」
ことで、柔軟に変更できるようにしており、それが次章の「事例の解説」節で述べる「モデル化」です。
オブジェクト指向は「難しい」と言われるのは何故?
オブジェクト指向は「難しい」「分かりにくい」という話をWeb上で多く見かけます。
この根拠には諸説ありますが、オブジェクト指向経験が10年以上あっても「カプセル化の困難さ」には苦労するようです。
カプセル化とは対象を抽象化してデザインすることです。
一般的な抽象化の概念と同じで、
「複数のものに共通する項目を挙げる」
ことで、これをプログラミングに応用し、設計していくことが非常に難しいのです。
(抽象化そのものも難しいですが、それを開発において最も効率的に行うための設計が困難です)
また、オブジェクト指向プログラミングの初心者にとって、
・馴染み深い「手続き型」とは異なるプログラミングスタイルであること
・設計段階ではフローチャートでなくUMLが使われること
・カプセル化や継承・ポリモーフィズムなどの特異で抽象的な概念の理解
など多くの障壁があると考えられます。
事例で学ぶオブジェクト指向プログラミング
オブジェクト指向プログラミングの解説記事は多いですが、具体的なイメージが沸かないと感じる人も多いのではないでしょうか。
典型的なものは「オブジェクト指向とは何か」を抽象的に説明し、続けてオブジェクト指向プログラミングに言及するタイプの解説記事です。
そこで、ここでは抽象的な説明は極力避け、
「皆さんが良く知っているゲームをオブジェクト指向プログラミングで開発する」
事例を通して、具体的なプログラミングスタイルを疑似体験して頂きたいと思います。
利用するゲーム
説明に使うパズルは、皆様が子供のころ遊んだ方も多い「15パズル」です。
15個の正方形タイルが4×4並べられるケースに収まっており、1つのマスが空いているもので、各タイルには1〜15までの数が書かれたものです。
初めはランダムに配置されていますが、1つ残されたタイルの空きを利用してタイルを上下左右に動かして1から15まで順番通り並ぶようにするものです。
ここでは、プログラミング環境としてVisual Studioを想定して作ります。
事例をオブジェクト指向でプログラミング
ここでは、「15ゲーム」をオブジェクト指向でプログラミングする手順を紹介します。
プログラミングは、前半の
「ひな型となるオブジェクトを定義するフェーズ」
と、後半の
「ひな型を使ってプログラムを完成させるフェーズ」
に分かれます。
先ず、「ひな型となるオブジェクトを定義するフェーズ」は以下の4つのステップからなります。
以下に「Buttonクラス」という用語が出てきますが、選択された「ボタン」オブジェクトにはVisual Studioが定義したボタンに関する記述があり、その記述を指すものです。
(ステップ1)CustomButtonクラスを作ります。
既存のオブジェクトを使って新しいオブジェクトを作ることを「継承」と言います。
そこで、Buttonクラスのオブジェクトを継承して作られた新しいオブジェクトのクラスをCustomButtonとします。
今回はこのCustomButtonをタイルに見立てて作っていきます。
この時、CustomButtonは、通常のButtonに出来ること
(ボタンを押せる。ボタンのビジュアル。ボタンを押すとビジュアルが変わるなど)
は、全て網羅されています。
これが継承です。
(ステップ2)CustomButtonクラスに「タイルのひな型」に必要なデータフィールドを追加します。
この時、考えることとしては、
「通常のボタンにはできず、今回のタイルに見立てたボタンだけで出来ること」
です。
具体的には、
・Position:ボタンのケース上の位置を示すもので、1から16の値を持つ
・isMovable:ボタンが空白の16番目と交換可能な位置にあるか否かを示す
という2つのデータを持つ「フィールド」を追加することになります。
(ステップ3)CustomButtonクラスにコンストラクタを定義します。
クラスとして定義されたオブジェクトはプログラムを実行する時に生成され、生成されたオブジェクトの実体を「インスタンス」と呼びます。
15パズルでは、15個のタイルと空白の16番目のタイルの合計16個のインスタンスを実体化することになります。
コンストラクタとはインスタンスを初期設定するためのコードで、タイルに表示する文字のフォントやisMovableの値などを設定します。
(ステップ4)CustomButtonクラスにメソッドを定義します。
メソッドとは、インスタンスに実体化したとき、各インスタンス固有の振る舞いをさせたいときに定義するものです。
これらは、メソッド内にコード化されており、プログラムから引数を指定して呼び出すことができます。
例えば、Initialize()という名前のメソッドは個々のインスタンスによって異なるNameとPositionのフィールドの値、表示する文字、位置などを定義するのに使われます。
ひな型を使ってゲームを完成させるフェーズ
次に、「ひな型を使ってゲームを完成させるフェーズ」は次のように進めます。
ひな型のタイル16個をForm1に4×4配置し、・・・、Form1をLoadすることで画面に表示されるようになれば、ゲームは完成です。
このために、Form1のLoadイベントハンドラによって実行されるメソッドに、
・myCustomButtonのインスタンスを16個作り、各ボタンを初期化すること
・16個目のボタンは空白なので、VisibleプロパティをFalseにして非表示にすること
などと書きます。
ここで、myCustomButtonはCustomButtonを配列にしたもので、以降の処理を簡素化する効果があります。
また、myCustomButton_ClockメソッドにはCustomButtonに定義されているMoveメソッドを呼び出して位置交換を実施することを書きますが、これは自分自身と空白タイルとの位置交換をするためです。
プログラミングスタイルの解説
上の事例で述べたように、オブジェクト指向プログラミングのプログラミングスタイルには
「モデル化」
「ひな型となるオブジェクトを定義する」
「ひな型を使ってゲームを完成させる」
の3つのフェーズがあります。
「モデル化」フェーズでは、データを整理して
「必要なオブジェクトを作成して、それらを使って一つのプログラムにする」
ことの筋道を立てています。
この例では、データを整理して
・元になるタイルは1種類で、15個のタイルは表示だけを1~15にしたもの
・空白もタイルの一つで、同種の元タイルから作られたもので表示が空白のもの
であるとしています。
さらに、
・このような16個のタイルが最初からケースに4×4配置されていること
・ゲームの進行に当たっては、タイルを物理的に動かす代わりに「セルの状態を遷移させ、表示を切り替える」ことでセルが移動している風に見せること
・タイルは隣接するタイルが空白の場合に、表示内容を交換できること
という風にモデル化しています。
「ひな型となるオブジェクトを定義する」フェーズでは、ひな型として使うオブジェクトのクラスには、全ての「タイル」に共通するデータ値やデータ項目、動作は勿論、共通しないものも記述します。
なお、タイル毎に個別に設定したい項目があったり、異なる動作をさせたりしたいというニーズには、プログラムの引数やInitialize()によって対応します。
「ひな型を使ってゲームを完成させる」フェーズでは、ゲームの完成形に要求される
「フォームLoad時の初期設定」
「タイルをクリックした時の動作」
などが設定されます。
なお、この事例では触れていませんが、本格的なシステムを開発する際はモデリングの際にUML(Unified Modeling Language)でシステムの分析結果と設計結果を図示することをお勧めします。
これは、手続き型言語によるプログラミングではフローチャートで設計図を表しますが、オブジェクト指向プログラミングでシステム開発する際にはUMLで設計図を表すことが一般的だからです。
高度な開発もAMELAなら低単価で叶う
今回は、多くのエンジニアが躓く、オブジェクト指向プログラミングについて触れてきました。
内容的に、ある程度プログラムがわかる人を対象として書かせていただきましたので、難しいと感じる人も多いでしょう。
Javaなどのプログラミング言語では、このオブジェクト指向プログラミングが用いられることが多く、大規模な開発に向いている手法です。
ただ、国内での開発でこれらをきちんと考慮した開発は、非常に高額なものになります。
AMELAでは、オフショア開発により、同じ品質のシステム開発を非常に安価で提供することができます。
是非、一度ご相談いただければと思います。