Processingで学ぶ 実践的プログラミング専門課程

第15回独立したクラスの作り方

導入

オブジェクト指向の学習をしています。連載第13回と14回では、既存のクラスの便利さや使い方を学びました。今回から数回に渡って、クラスを作成する方法をいくつか紹介します。クラスを上手に使えば、コーディングがとても楽になります。

展開

新しいクラスを作成する方法は、次の方法が考えられます。

  1. 独立したクラスを作る
  2. 別のクラスを継承するクラスを作る
  3. インタフェイスを実装するクラスを作る
  4. 別のクラスを内包し委譲をするクラスを作る

いずれの方法をとるにせよ、クラスを作成するメリットはコードブロックを部品化できることです。遥か古代のプログラミング言語のようにクラスを使わないコードは、読む者にとってはまるで雲や霧のようです。つかみどころが無く、形をとらえるのが難しく、取り扱いに苦労します。クラスを使えば、コードがまるで手応えのある瓶に入ったように、取り扱いやすくなるのです。

1.~4.の方法を学ぶために、これから数回に渡って次のテーマに毎回取り組みます。

テーマ:データファイルを読み込むクラスを作成する

「テキスト形式のデータファイルから設定情報を読み込むクラスを作る」という案件があるとします。データファイル形式の変更や、実装方法の変更に柔軟に対応できるようなクラスを作りましょう。

今回はこのテーマを達成するために、1.にあたる「独立したクラスを作る」方法をとります。次回は3.にあたる「インタフェイスを実装するクラスを作る」方法を、その次の回で2.と4.をあわせて「継承と委譲をするクラスを作る」方法をとります。

独立したクラスを作る

まずは最も単純に、独立したクラスを作ってみましょう。 そのために、作成したクラスがこんなふうに動いてほしいというテスト用のsketchを書きます。まだ目的のクラスがありませんが、testメソッドの中で目的のクラスのインスタンスを作成し、簡単なテストコードを置きます。このテストに合格するようなクラスを作ろうとしているのです。

TestAppInfoLoader.pde
//Test AppInfoLoader class
private final String TARGET_CLASS_NAME = "AppInfoLoader";
private final String SOME_TROUBLE = TARGET_CLASS_NAME + " : "
                                  + "Some trouble happend.";
void setup(){
  test();
}

void test(){
  noLoop();
  println("Test Start.");
  assert AppInfoLoader.CLASS_NAME.equals(TARGET_CLASS_NAME)
       : SOME_TROUBLE;
  AppInfoLoader ail = new AppInfoLoader();
  assert ail.CLASS_NAME.equals(TARGET_CLASS_NAME);
  println("All Test Done.");
  exit();
}

では、テストに合格するようなクラスを、AppInfoLoader.pdeとして書きましょう。次の手順にしたがってProcessingのIDEで新しいタブを作成してください。

  • IDEに表示されているTestAppInfoLoaderタブの隣にあるドロップダウンメニューボタンをクリックし、New Tabを選択します。ファイル名はAppInfoLoaderとします.pdeは打ち込む必要がありません。IDEが自動で追加して保存します⁠⁠。
AppInfoLoaderクラスのために新しいタブを作成する。
画像

AppInfoLoaderとして、最初に次のコードを書いてみます。

一番最初のAppInfoLoader.pde
public class AppInfoLoader{
  public static final String CLASS_NAME = "AppInfoLoader";
}

ここで今回読み込むデータファイルを次のCONFING.TXTとします。このファイルは、コンマで区切られたテキストファイル(CSV)です。このファイルをテキストエディタで作成して、ProcessingのIDEにドロップすれば、sketchフォルダ内のdataフォルダに追加されます。

CONFIG.TXT
VERSION,1.0

[作業] CONFIG.TXTを読み込むコードと、メソッドgetVersionを書きましょう。これはCONFIG.TXTに記録されているバージョンナンバーを文字列で返すメソッドです。ファイルの読み込みにはloadStringsメソッドを使いましょう。ファイル名はAppInfoLoader.pdeこれをテストするsketchファイルをTestAppInfoLoader.pdeとしてください。この作業を今回の演習1とします。

最終的に、AppInfoLoader.pdeは次のように書けます。

このAppInfoLoader.pdeTestAppInfoLoader.pdeのスケッチフォルダ内に配置してください。CONFIG.TXTAppInfoLoader.pdeを読み込んだProcessingのIDE上にドラッグ&ドロップしてください。

実装が異なる別のクラスを作成する

次に、動作に違いや問題が無くても、ユーザから見えない実装部分の変更をしたくなった場合を考えてみましょう。

たとえば、AppInfoLoader.pdeではloadStringsメソッドを使いましたが、エラーがあった場合の例外処理を加えたいならばBufferedReaderクラスを使います。そして将来のためにAppInfoLoaderクラスをそのまま残しておきたいならば、別のクラスを作ることになります。

ここでは、これらのことを踏まえて、BufferedReaderクラスを使ってAppInfoLoader2クラスを書いてみましょう。

[作業] CONFIG.TXTを読み込むコードと、メソッドgetVersionを書きましょう。ファイルの読み込みにはBufferedReaderクラスを使ってください。ファイル名はAppInfoLoader2.pdeとしましょう。テストコードはTestAppInfoLoader.pdeに追加しましょう。先ほどのテストコードと区別するために、TestAppInfoLoader2.pdeとファイル名を変更しましょう。これを今回の演習2とします。

AppInfoLoader2というクラス名はよくありません。AppInfoLoaderとどう違うのか、名前から判断できません。これらのクラスを使うコードの文脈から、それぞれのクラス名を再検討するべきです。

AppInfoLoader2クラスと、そのテストコードは次のように書けます。

メソッド名と戻り値、場合によっては引数も一致させておけば、設定ファイルを読み込むクラスの実装を変更しても、そのクラスを利用する側のコードの変更はインスタンスの宣言部分のみで済みます。 現状のAppInfoLoader2クラスは、try...catch節で例外の内容をコンソールに出力することしかさせていませんので、わざわざBufferedReaderクラスを使った価値がありません。Processingで用意されている便利なメソッドを利用せずに、Java言語のクラスやメソッドを利用する場合は、本当にその必要があるのかどうかよく検討しましょう。

新たに独立したクラスを作成する利点

十分小さいコードならば切り分けないほうが見通しが良い

今回は、新たなクラスを作成して利用する場合の手順を紹介しました。今回紹介したような程度のプログラミングであれば、すべてsetupメソッド内に記述しても構わないのです。新たにクラスを書くということは、管理する要素を増やすことになるのですから、必要なければ避けるべきです。すべてのコードが一カ所にあれば、目的のコードを探す手間が省けるように思えます。しかしこの考え方はすぐに破綻します。長いコードは読めたものではないからです。

1画面に収まらないコードは切り分けると見通しが良くなる

一画面に収まらないほど長いコードはクラスに切り分け、まとめることで、クラスを使わない場合に比べて見通しが良くなります。見通しが良くなるのは、コードが「大枠として書かれた部分」「詳細な部分」に切り分けられるからです。大枠の部分を読んでいるときに、詳細な部分は見えないほうがコードを理解しやすいのです。

隠蔽とカプセル化

大枠を見ているときに、見える必要の無いコードが見えないようにすることを「コードを隠蔽する」と呼びます。 もう一歩進めて、コードの中で抽象度の低いフィールドやメソッドを、クラスの中のプライベート要素とし、抽象度の高い部分のコードから直接操作させないようにすることをカプセル化と呼びます。設定ファイルを読み込むクラスのコードが具体的にどうなっているのか、クラスを利用する側にとっては問題ではありません。クラスを利用する側にとって問題なのは、目的の情報が正しく得られるかどうかです。コードが見えている必要がないのです。ですから隠し、不用意に操作されることを防ぐのです。

オブジェクト指向プログラミング言語はプログラミングを楽にする道具立てを持つ

クラスを作るというステップの精神的敷居を超えてしまえば、むしろまとまったコードを書く場合はクラスを作ったほうが楽だと思うようになります。その昔、構造化プログラミング花盛りし頃ならば「コードをモジュール化する」とか「関数を書く」と言っていた作業が、⁠クラスを書く」ということに発展したと言えます。かつては関数をひとまとめにしたライブラリがありましたが、それをもっとお手軽に作成できるようにしたのがクラスでしょう。さらに現在のオブジェクト指向プログラミング言語、特にJava言語では、クラスをまとめて取り扱うパッケージという仕組みがあります。コードの抽象化の道具立てが大変使いやすくなったと思います。ありがたいものです。

演習

「展開」での[作業]が今回の演習になります。

まとめ

  • 独立したクラスの作成手順を学習しました。
  • 新たにクラスを作成する利点を紹介しました。
  • オブジェクト指向の便利な仕組みである隠蔽とカプセル化を紹介しました。

学習の確認

それぞれの項目で、Aを選択できなければ、本文や演習にもう一度取り組みましょう。

  1. 独立したクラスの作成手順が理解できましたか?
    1. 理解できた。気持ちよく納得した。
    2. 理解できた。しかし、今ひとつスッキリしない。
    3. 理解できない。
  2. 新たにクラスを作成する利点が理解できましたか?
    1. 理解できた。気持ちよく納得した。
    2. 理解できた。しかし、今ひとつスッキリしない。
    3. 理解できない。
  3. 隠蔽とカプセル化の利点が理解できましたか?

    1. 理解できた。気持ちよく納得した。
    2. 理解できた。しかし、今ひとつスッキリしない。
    3. 理解できない。

参考文献

  • 『本格学習Java入門[改訂新版]』⁠佐々木整 著、技術評論社
    • Java言語の基本的な文法が良くまとめられています。また、大変広い範囲をカバーしているので、はじめてJava言語に触る方が、Javaがどんな言語なのかを知るために役立つ資料になるでしょう。
  • 『ずばりわかる! Java Javaの良いコード、悪いコード(日経BPパソコンベストムック⁠⁠日経ソフトウエア 編著、日経BP社
    • 日経ソフトウエア誌に掲載された特集を集めたムックです。2006年発行と少々古くなりましたが、各トピックともにコンパクトにまとまっており、Java言語でコーディングをする際の具体的な指針やその例が掲載されています。

演習解答

解答のコードは「展開」にて掲載しています。

ただし、このコードは一例にすぎません。そのため、時間を区切ってその時間内で可能な工夫を凝らしてください。たとえば、次のような工夫の余地があります。

  • 設定情報ファイルCONFIG.TXTCONFIG.DATになっても良いように、AppInfoLoaderクラスに設定情報ファイル名を受け取る引数付きのコンストラクタをつける。
  • 設定情報ファイル名を受け取るメソッドをつける。
  • 設定情報のデータの区切り文字が、コンマではなく空白文字等任意のものを指定できるようにする。
  • 2つのAppInfoLoaderクラスのクラス名を、機能に応じたよりふさわし名前に変更する。

おすすめ記事

記事・ニュース一覧