プロデルで始める日本語プログラミング言語入門(#9) 「オブジェクト指向とは」


連載の9話目になりました。今回は、「オブジェクト指向」についてご紹介します。すでにプロデルをよく使っている方で「難しい」と感じる所は、このオブジェクト指向に関する所なのではないかと思います。

今回は、プロデルでのオブジェクト指向プログラミングの特徴を説明していきたいと思います。知るべき言葉が多く、説明が長くなりますが、プログラムを眺めたり実行するだけでも大丈夫なので、ぜひ読み進めて貰えたら嬉しいです。

オブジェクト指向が分かれば、プロデルの魅力がよりよく分かるはずです。

オブジェクト指向とは

オブジェクト指向とは、とても簡単に説明すると、ソフトウェアの構成要素を物に見立てて、物の単位で振る舞いとデータを整理してプログラミングする考え方です。

オブジェクト指向プログラミングを例を挙げて考えてみます。

例えば「車」という物があるとします。車は、「走る」「止まる」と言った振る舞いができます。また「色」「名前」といったデータ(情報)を持っています。プログラムを使って、車に振る舞いを指示したり、情報を設定したり取得したり、他の物を組み合わせて操作したりすることで、ひとつのアプリを作っていきます。

このようにプログラムの振る舞いとデータをオブジェクトとしてまとめて、プログラムを組み立てていく考え方をオブジェクト指向と言います。

プロデルは、オブジェクト指向プログラミングを全面的に採用した日本語プログラミング言語です。旧シリーズのTTSneoと比べて、オブジェクト指向を踏まえた言語仕様へと改良され、豊富な機能が体系的に整理されて便利に利用できるようになりました。

オブジェクト指向は、C++言語をはじめとしてJavaやObjectiveC, Ruby, C#など最近の多くのプログラミング言語でも採用されている考え方です。

※プログラミング言語のタイプによって考え方や説明が違うので、今回は「プロデルでのオブジェクト指向の考え方」と理解すると良いかと思います

話は逸れますが、プロデルロゴに使われている青の立方体は、オブジェクトを表現しています。プロデルがオブジェクト指向プログラミング言語であると同時に、オブジェクト指向がプロデルで大切な要素の一つであることが込められています。

種類とは

種類(しゅるい)とは、オブジェクトを作るために必要なオブジェクトの設計図です。「クラス」と呼ばれることもあります。

プロデルの種類では、振る舞いとして手順(メソッド)を、データとして変数(フィールド)を定義します。他にも定義できる構成要素があります。

とりあえず書いてみよう!

「種類」を定義しましょう。ここでは「車」という種類を定義します。「車」種類には、「名前」という変数と「走る」という手順を定義します。

車とは
  +名前

  走る手順

  終わり
終わり

種類を定義するには、「種類宣言文」を書きます。種類宣言文では、「~とは」から「終わり」までの間が一つの宣言文です。この種類宣言文の中に、必要な変数宣言と手順宣言文を書きます。

種類には、次のような構成要素(メンバー)があります。

  • 手順 (メソッド)
  • 変数
  • 設定項目 (プロパティ/ゲッター・セッター)
  • イベント手順

これらのメンバーは、「種類宣言文」の中で定義できます。

上記のプログラムでは、「車」という種類を定義しています。これで設計図が出来上がりました。

種類とインスタンス化

種類は、オブジェクトの設計図にあたるものですので、設計図のままでは使えません。「作る」文を使って、種類定義をもとにメモリ上にオブジェクトを作ることで、使えるようになります。

【変数名】という【種類名】を作る

変数名には、オブジェクトの名前を指定しておき、【種類名】には、宣言した種類の名前を指定します。

グリーンカーという車を作る
グリーンカーの名前は、「太郎の車」
グリーンカーの名前を表示する

車とは
  +名前
終わり

種類からオブジェクトを作ることをインスタンス化と言います。「作る」文を呼び出した度にインスタンス化されて、オブジェクトが作られます。インスタンス化されると、メモリ上にそのオブジェクトを操作するための作業場所が確保されます。

次の図は、「車」という種類(白抜きの図形)からオブジェクトを作って(インスタンス化して)、作ったオブジェクトに対して「太郎の車」「花子の車」と言った名前をそれぞれに設定したことを表しています。

作られたオブジェクトは、設計図は同じ(定義された手順と変数は同じ)ですが、「名前」変数に格納されている内容は、オブジェクトごとに別々に保持されています。

次のプログラムは、上の図のように「太郎の車」と「花子の車」を作るプログラムです。「太郎の車」に加えて、もう一つ車を作り、その車の名前を「花子の車」としてみます。グリーンカーは「太郎の車」で、オレンジカーは「花子の車」としてみます。

グリーンカーという車を作る
グリーンカーの名前は、「太郎の車」

オレンジカーという車を作る
オレンジカーの名前は、「花子の車」

グリーンカーの名前を表示する
オレンジカーの名前を表示する

車とは
  +名前
終わり

このように設計図となる種類(クラス)を定義して、それをインスタンス化してオブジェクトを作るというプログラミングの考え方を「クラスベース」のオブジェクト指向プログラミングと言います。プロデルは、クラスベースのオブジェクト指向プログラミング言語です。一方で、JavaScriptのような「プロトタイプベース」のプログラミング言語もあります。

種類変数

すでに登場しましたが、種類が持つ変数のことを「種類変数」といいます。種類変数を定義するには、種類宣言文の中で「+」「-」「#」といった記号で始まる変数宣言文を書きます。変数宣言文では、これらの記号の後に変数名を書きます。後ほど詳しく説明します。

ここでは『+名前』と変数宣言文を書いて、種類変数を定義しています。

車とは
  +名前
終わり

種類手順

種類の振る舞いとして手順を定義するには、種類宣言文の中に、以前紹介した手順宣言文で手順を定義します。このように定義すると、車に対して「走る」という振る舞いを定義できます。

車とは
  走る手順
    「ブーン」と表示する
  終わり
終わり

種類手順の呼び出し文

今度は、定義した走る手順を実行してみましょう。オブジェクトに対してその種類で定義した手順を実行するには、次のような書式で手順呼び出し文を書きます。

【変数名】:【手順名】

【変数名】には、手順を実行させたいオブジェクトの名前を指定します。このオブジェクトをレシーバと言います。「:」を使うと指定したレシーバオブジェクトに対して手順を実行させることができます。

例えばグリーンカーに対して、走る手順を実行されるには、次のように書きます。

グリーンカーという車を作る
グリーンカー:走る

車とは
  走る手順
    「ブーン」と表示する
  終わり
終わり

レシーバ補語

「:」で振る舞いを指示したいオブジェクトを指定できますが、より日本語らしく書けるようにレシーバ補語を定義しましょう。

レシーバ補語とは、手順でその補語に対応するオブジェクトがレシーバであることを指し示している補語のことです。

手順定義でレシーバ補語を指定するには、「自分」キーワードを使います。自分+助詞の形式で指定すると、その助詞に対応するオブジェクトがその手順でのレシーバとなります。

例えば、次のように「走る」に「自分が」というレシーバ補語を指定すると、「~が」に指定したオブジェクトがレシーバになります。

マイカーという車を作る
マイカーが走る

車とは
  自分が、走る手順
    「ブーン」と表示する
  終わり
終わり

このように「自分」キーワードを使ってレシーバ補語を定義すると、より日本語らしい文でオブジェクトを操作するプログラムが書けます。

設定項目

「設定項目」とは、オブジェクトの性質を設定したり取得したりするためだけを目的にした特別な手順です。扱い方は、種類変数と似ていますが、設定項目には設定したり取得したりする時に手順と同じように何かしらの処理を入れることができます。

次のプログラムでは、「購入年」という設定項目を定義しています。

設定する手順では、『設定値』にこれから設定項目に設定するべき値が保持されています。この手順で「年」変数に『設定値』を代入します。代入する前には、設定値が1970以下にならないように判断して、1970年以下だった時には、エラーメッセージを表示するようにしています。

また取得する際の手順では、「年」変数にある値を返します。「年」が未指定(無)の時には代わりに「不明」と返すようにしています。

グリーンカーという車を作る
グリーンカーの購入年は、2010
グリーンカーの購入年を表示する

車とは
	-年

	購入年という属性
		設定する手順
			もし設定値が1970以下なら「[設定値]は、古すぎます」というエラーを発生させる
			年は、設定値
		終わり

		取得する手順
			もし年が無なら「不明」を返す
			年を返す
		終わり
	終わり
終わり

『グリーンカーの購入年は、2010』の部分をコメントにしたり、1965などに変えて実行してみてください。

//グリーンカーの購入年は、1965
グリーンカーの購入年は、1965

このように設定項目は、設定する前に正しい値かどうかチェックしたり、取得する時に状態に応じて結果を変えることができます。この点が種類変数と異なります。

なお、設定項目宣言文は、次のように「設定する手順」と「取得する手順」とを単独で宣言することもできます。設定か取得かの片方だけを定義するときに便利です。

車とは
	-年

	購入年を設定する手順
		もし設定値が1970以下なら「[設定値]は、古すぎます」というエラーを発生させる
		年は、設定値
	終わり

	購入年を取得する手順
		もし年が無なら「不明」を返す
		年を返す
	終わり
終わり

オブジェクト指向の三大要素「カプセル化, 継承, 多態性」

さて、プログラミング言語の世界では、よくオブジェクト指向の三大要素として次の特徴が説明されています。

  • 継承する
  • 多態性を活用する
  • カプセル化する

それそれの特徴についてプロデルのプログラムでご紹介します。

A. 種類の継承

すでにある種類の設計図を参考にして、別の種類を定義することを「継承する」と言います。

例えば、次の図のように、すでに定義してある「車」種類を継承して「救急車」種類や「スーパーカー」種類を定義する、といったことができます。

継承した2つの種類は、「車」で定義した変数や手順を引き継いた上で「救急車」種類や「スーパーカー」種類にしかない変数や手順を、加えて定義できます。

例えば次のプログラムのように、「車」種類に「鳴る」手順を定義します。また「車」を継承した「救急車」という種類を定義します。救急車には、「サイレンする」という手順を定義します。

青い車という車を作る
青い車の名前は、「青い車」

白い救急車という救急車を作る
白い救急車の名前は、「白い救急車」

青い車が鳴る
白い救急車が鳴る
白い救急車がサイレンする

車とは
  +名前
  自分が、鳴る手順
    「[名前]: プップッー」を表示する
  終わり
終わり

救急車とは
  車を受け継ぐ
  自分が、サイレンする手順
    「[名前]: ピーポーピーポー」を表示する
  終わり
終わり

このプログラムの8,9行目で「白い救急車」に対して、「鳴る」手順と「サイレンする」手順を呼び出しています。このように「救急車」種類の種類宣言文の中には「サイレンする」手順のみが定義されていますが、車を継承しているので「鳴る」手順も使えます。

B-1. 多態性を活用する (種類の抽象化)

継承を利用することで、2つ以上の種類で共通している変数や手順をまとめることができます。

今度は、例えば「人」という種類を定義します。人には「名前」という変数があり、人の名前を記憶しておきます。また「人」を継承した「家族」種類と「友人」種類を定義することにします。

「家族」種類と「友人」種類は、それぞれ「人」種類を継承して、どちらでも「名前」変数を利用できるようにします。

このような設計の種類をプログラムに書くと次ようになります。

家族である「健太」というオブジェクトと、友人である「山田さん」というオブジェクトを作り、それぞれの「名前」変数に「健太」と「山田さん」を代入します。

また「挨拶する」手順を定義して、「相手」引数に指定した人の名前を表示するようにプログラムします。

健太という家族を作る
健太の名前は、「健太」
山田さんという友人を作る
山田さんの名前は、「山田」

健太に挨拶する
山田さんに挨拶する

[相手]に挨拶する手順
	「[相手の名前]さん、こんにちは」と表示する
終わり

人とは
	+名前
終わり

家族とは
  人を継承する
終わり

友人とは
  人を継承する
終わり

実行すると、相手に指定した人に応じてメッセージが表示されます。

「挨拶する」手順に注目すると、「相手」引数には、家族のオブジェクトか友人のオブジェクトかのどちらかが入るはずです。どちらにしても「人」を継承した種類のオブジェクトですので、相手には必ず「名前」変数があります。そのため、名前を調べてメッセージを表示できます。

このように「家族」と「友人」のように異なるオブジェクトについても「挨拶する」手順の中では、同じ「人」であるとみなして名前を調べることができます。

このような使い方ができるのが多態性の特徴の一つです。

B-2. 多態性を活用する (手順のオーバーロード)

一つの種類には、同じ名前を持つ手順を二つ以上宣言できません。ただし手順の場合は、実補語の個数や、実補語の仮引数のデータ型、実補語の助詞が異なれば、同じ手順名でも複数定義できます。このように同じ手順名を複数定義することを手順のオーバーロードと言います。

オーバーロードを使うと、同じ名前の手順について、実補語(引数)に指定するオブジェクトごとに実際の動作を変えるといったことができます。

例えば、次の図のように、「犬」種類と「人」種類を定義します。人には、「家族」と「友人」がいます。

「犬」種類には「見た」手順を定義します。犬は、家族を見ると「きゅんきゅん」となつきますが、友人を見ると「ワン」と吠えるようにプログラミングしてみます。

犬として「ぽち」、家族として「健太」、友人として「山田さん」を作ります。ぽちが健太を見た時と、山田さんを見た時の手順を、手順のオーバーロードを使って定義します。

ぽちという犬を作る
健太という家族を作る
山田さんという友人を作る

ぽちが健太を見た
ぽちが山田さんを見た

犬とは
  自分が、友人である[人]を、見た手順
    「ワン!ワン!ワン!」を表示する
  終わり

  自分が、家族である[人]を、見た手順
    「きゅうきゅん」を表示する
  終わり
終わり

人とは

終わり

家族とは
  人を継承する
終わり

友人とは
  人を継承する
終わり

実行してみます。5行目で、犬である「ぽち」は、家族である「健太」を「見た」時、「きゅんきゅん」と鳴きます。一方、6行目で、友人である山田さんを見た時、「ワンワン」と吠えます。

このように同じ「見る」という手順でも、引数を与えられたオブジェクトによって振る舞いを変えることができます。これも多態性の特徴のひとつです。

C. カプセル化する

プログラムが複雑になると、種類の中に変数や手順などの定義をたくさん書くことになります。その際に、手順の中で計算やデータを処理するために一時的に使う変数や手順を宣言する必要もあります。このような種類の中でだけ使う定義は、種類の外から意図しない状態で利用できてしまうとバグの原因になったりして困ったことになります。

本来、外から使うはずがない変数や手順を誤って使わないように、種類内の定義には、公開範囲で指定できます。公開範囲とは、種類をひとつのまとまりと考えたときに他の種類から利用できるようにするかどうかの度合いのことです。公開範囲を決めることで、その変数や手順を外から使えないように設定できます。

このように種類の中だけで使う変数や手順を、手順の外から利用できないようにすることを「カプセル化」といいます。

公開範囲は、変数や手順定義の冒頭に次のような記号を付けて宣言します。

  • 「+」(公開, 他の種類から利用できる)
  • 「-」(非公開, 自分の種類の手順からのみ利用できる)
  • 「#」(継承した種類に限り公開)

なお、省略した場合は、「+」として扱われます。

カプセル化をプログラム例を挙げて説明します。次の例では、暗証番号が分からないとドアが開かない「車」を作ります。「車」という種類で「暗証キー」という非公開の変数を定義します。また「暗証番号を設定する」という設定だけができる設定項目を定義します。

次のプログラムでは、「マイカー」という車に「名前」や「暗証番号」を設定しています。「名前」は、公開された変数のため取得することができますが、「暗証番号」は、取得するための手順がないので取得できず、エラーとなります。また、車だけが知っている「秘密キー」変数も公開されていないので取得できず、エラーとなります。

「秘密キー」変数は、外からは取得できませんが、車の種類定義の中の手順では普通に設定したり取得したりできます。

マイカーという車を作る
マイカーの名前は、「ベンツ」
マイカーの色は、「黒」
マイカーの持ち主名は、「カイル」
マイカーの暗証番号は、「1212」

マイカーの名前を表示する
マイカーの暗証番号を表示する //見られない
マイカーの秘密キーを表示する //見られない
マイカーが「1111」で開くかどうか
マイカーが「1212」で開くかどうか

車とは
  +名前
  +色
  +持ち主名:文字列
  -秘密キー:整数

  暗証番号を設定する手順
    秘密キーは、設定値
  終わり

  +自分が【キー】で、開くかどうかを判定する手順
    もしキーが秘密キーなら
      「この車の持ち主です」を表示する
    でなければ
      「この車の持ち主でありません」を表示する
    もし終わり
  終わり
終わり

静的種類(シングルトン)

「作る」文でインスタンス化せずに種類の変数や手順を使うこともできます。「単一種類」宣言を付けることで、オブジェクトを生成せずに利用できる種類を明示的に定義できます。

スカイツリーの高さを報告する

//次のように書くとインスタンスは生成できません
タワーというスカイツリーを作る
タワーの高さを報告する

スカイツリーとは
    単一種類
    +高さ=634
終わり

プロデルデザイナの「ウィンドウの設計」画面で自動的に生成される「メイン画面」種類では、「作る」文を使わずに「メイン画面を表示する」とシングルトンの種類手順を呼び出しています。

イベント手順を定義する

種類には、イベント手順を定義できます。イベント手順は、種類での処理中に発生した状況を、種類の外のプログラムに通知して外で処理を実行できるようにする仕組みです。

イベント手順の設定

「作る」式で【変数名】を指定すると、生成されたオブジェクトのイベント手順と、同じ種類宣言文内にある特定の法則で名付けられた手順がイベント手順として対応付けられます。イベント手順に対応付けられる手順は、次のような名前の法則で定義された手順です。

  • 《変数名》の《イベント手順名》時
  • 《変数名》が《イベント手順名》時

イベント手順の定義

イベント手順を定義すると、種類内部で発生したイベントを種類外部の手順で受け取ることができます。

種類宣言文の中で「発生する」文を使ってイベント手順を定義できます。

また、定義したイベント手順を発生させるには、「発生させる」文を呼び出します。

マイカーという車を作る
// イベント手順を設定します
マイカーの到着した時の手順は、到着した
マイカーが到着する

到着した手順
  「到着しました。[改行][この時の緯度][この時の経度]」を情報アイコンで表示する
終わり

車とは
  // イベント手順を定義します
  到着した時に発生する

  【自分】が、到着する手順
    // イベント手順を発生させます
    情報という到着イベント情報を作る
    情報の緯度は、35.681382
    情報の経度は、139.766084
    情報で到着した時を発生させる
  終わり
終わり
 
// イベント手順が発生したときに使用する付加情報
到着イベント情報とは
  イベント情報を継承する
  +緯度
  +経度
終わり

「イベント情報」は、イベント手順を発生させた時に付加する情報を入れておくための種類です。「到着イベント情報」では、「到着した時」のイベント手順が発生した時の緯度と経度を設定しています。

オブジェクト指向プログラミングは難しい!?

今回、オブジェクト指向を分かりやすく紹介するために、車や人などのコンピュータに関係が無い物に例えて紹介しました。概念を説明するためにコンピュータとは無関係な例を挙げているので、何となく難しいと思った方もいるかと思います。

実は、今回までの連載を読まれた方は、みなさんすでにオブジェクト指向プログラミングをしています。なぜなら、GUI部品キャンバスの図形は、オブジェクト指向で設計されているからです。

例えば

  • GUI部品の「背景色」や「大きさ」などの設定項目で部品の見た目などを変えています。
  • 四角形や円と言った図形は「キャンバス図形」を継承して抽象化されています。
  • タイマーのオブジェクトに対して「開始する」「停止する」といった振る舞いを指示しています。

などなどオブジェクト指向なプログラムをこれまでたくさん書いてきました。

GUI部品や図形などを使うことができれば、それは立派なオブジェクト指向プログラミングです。オブジェクト指向に恐れずぜひ使いこなしてみてください。

まとめ

今回は、プロデルでのオブジェクト指向プログラミングについて紹介しました。
今回の記事を通じて、日本語っぽく手順を呼び出すプログラムを書く方法や、オブジェクト指向と日本語プログラミングとの相性の良さが分かって頂けたのではないでしょうか。

次回をお楽しみに!

※当ブログの記事の著作権はゆうとにあります。プロデルに関係が無い目的で、文章や図表,プログラムを複製したり改変して掲載することを堅く禁止します

  • いいね (8)
  • 続きを読みたい (10)

コメントを残す