オブジェクト指向超入門〜第2回〜
オブジェクト指向よりも前の時代のプログラミングスタイルでは、仕様をシステムでどのように実現するかという処理(手続き)がまずあって、その処理の結果としてデータが出来上がります。出来上がったデータは外部のDBなどに保存するなり、そのデータを元にまた別の処理を実行するなりして、全体としてのシステムが作られます。
こういうのを「手続き指向」などと呼んだりします。手続き指向では処理をまず最初に決めて、その処理の結果としてデータが作られる訳で、処理が主,データが従の関係になります。
こう書いても抽象的でピンとこない人が大半でしょうから、具体例を挙げながら説明します。なおここから先はC言語での実装例で説明しますが、単純な例なのでJAVAなどの他の言語しか知らない人でも容易に理解できると思います。もうひとつ念のために断っておくと、実装例のコードは文法的に間違っている場合があります。文法に忠実に書く事よりも論点を重視する為に細かい記法をあえて無視していますので、そのままコンパイラに通して「エラー出るじゃねえか!」と言わないように。
1.構造体を定義する
例として日付をデータとして保持したいというケースを考えます。C言語の変数には整数や文字などの基本的な型しか無いので、日付のようなデータを変数として保持したい場合にはちょっと工夫が必要です。そこで整数型の変数を3つ用意して、それぞれ
int yy; // 年
int mm; // 月
int dd; // 日
のように年月日を保持する事を考えます。このような変数は常に3つセットで使ってはじめて意味があるので、こういう場合にCでは「構造体」というものを定義します。
struct MyDate {
int yy; // 年
int mm; // 月
int dd; // 日
}
MyDateという名前の構造体を定義しました。(MyDateってダサダサな名前はどうなんだ、という意見は置いといて・・・)
いったんこのような定義を作ると、日付型という型があたかも最初から言語に用意されてたかのように変数を作れる訳ですよね。
MyDate today; // 本日の日付
MyDate birth; // 誕生日
todayやbirthといった変数は、それぞれがyy,mm,ddの3つのint値を持っています。これらを構造体の「メンバ」と呼びます。
今日は何日かと聞かれたら today.dd
あなたは何月生まれと聞かれたら birth.mm
のように、「変数名.メンバ名」という書き方で、どの変数のどのメンバを使うのかを指定します。
2.構造体を使う
このような変数を用意したら次にそれを使った処理を考えます。本日の日付と誕生日の差を求めて、この人が何歳なのか計算するという処理を書いてみます。
まずは準備として変数に値を代入します。
// 本日は2008年10月20日とする
today.yy = 2008;
today.mm = 10;
today.dd = 20;
// 生年月日は1970年8月5日
birth.yy = 1970;
birth.mm = 8;
birth.dd = 5;
続いて2つの日付の差を求めます。ここでは年齢を計算したいだけなので、月日はどうでもいいと考えて、
int age = today.yy - birth.yy;
これで「今年で何歳になる(なった)か」は簡単に求まりますが、今日現在で満何歳なのかを知りたいならこれでは駄目ですよね。
両者の月(mm)を比較して誕生日の方が大きかったら1歳減らす、月(mm)が等しかったら次に日(dd)を比較して・・・といった考慮が必要です。2つの日付の差分を求めるという単純な例ではありますが、それでも多少は気を付けなきゃいけない点があって、数行のコードになります。
いったんMyDateを定義してそれを使うようになると、日付の差分を求めるというのはいかにもシステムのあちこちで行うであろう処理だと容易に想像できます。その全ての箇所でいちいちこのような数行のコードを書くのは面倒くさいしバグの元になります。例えばプロジェクトに配属されたばかりの新人君にこの処理を書かせたら、うるう年の2月29日生まれの場合の考慮を、彼はちゃんと実装してくれるでしょうか。
そこでこのようなどこでも行うであろう処理は関数として切り出して、誰かが一度だけ書いてあげれば、他のプログラマはそれを呼ぶだけで済むから生産性が上がるよね、という考えで以下のような関数を用意してあげます。
int dateDiff(MyDate birth, MyDate today);
こういうのを共通関数などと呼びます。いったんこのような関数を作ると、差を求める以外にも日付を処理するケースは多々あって『ある日付の○日後の日付を求めたい』『当月の月末の日付を知りたい』『年を和暦に変換したい』などいろんな場所でいろんな要求が出てきます。それらを1つひとつ共通関数として用意してあげると、だんだんと関数の数が増えて充実していって『日付共通関数ライブラリ』なるものが出来上がります。
このようなライブラリはプロジェクトの資産となり、日付以外にも様々な『○○ライブラリ』が作られて、システムの生産性向上に寄与する訳ですね。
この考え方はオブジェクト指向でも何でもなく「構造化プログラミング」などと呼ばれ、オブジェクト指向よりもずっと前から提唱されているスタイルです。オブジェクト指向をわかってない人の大半は、実はこの段階で止まっちゃってるんですよ。この旧来のスタイルが染み付いててそこから脱皮できないからオブジェクト指向の本質が理解できないんですね。
繰り返しますが、「関数ライブラリ」の考え方はオブジェクト指向ではありません。←ここ何気にチョ〜大事!
すいません。cもHello worldをコンパイルしたことがあるくらいです(汗)
コンパイラーってのは、変数の型とコンパイルがまずもってめんどくさい。というのが正直なところですー。
いやもうプログラマのみなさんには謝るほか…(汗)