ページ

2008年11月21日金曜日

アルテルナータ可愛いよアルテルナータ

0 件のコメント:
仕事がちょっと修羅場中。
正確に言うと、修羅場になる可能性があるかもレベル。僕の腕にかかっている。
てか納期が短すぎんだよ…チクショウ…しかも見切り発車気味だし。僕一人で開発するには規模が少しデカイ。複数のシステムに関係するシステムゆえ、アプリケーション設計が開発速度に即座に影響する。効率の悪い作り方してたら時間だけが一向に過ぎていく。幸い、システム設計自体は考え抜かれた汎用さを有しているので、相当な仕様変更がない限りは大丈夫だと思うが、そんな汎用さをプログラムとして実現するのは結構大変。

でも僕は勉強して、『インターフェイスによるコーディング』を心がけてる。デザインパターンのコアになるような部分なんだが、頭の弱い僕では理解するのに時間がかかった。

僕が勤務する会社では、開発するシステムには主にSQLServerを使用する。
そのため、ヒヨッコの僕は始め、SQLServerとの連携をクラス化し、こんな感じにコーディングしようとしていた。

Dim DBCon as new myDBConnect(Me._ConnectionString)
If DBCon.IsConnect() Then
DBCon.ExecuteSQL(Me.sqlquery)
End If

って感じに。DBへのデータ挿入等々、細かい実装は myDBConnect クラスで書いてある。SQLを引数に渡してあげたり、あるいはメソッドを実行するだけで、DBへの様々な処理を実現していたわけだが、ある日上司からこういわれた。

「もしもネットワーク障害が原因でSQLServerへ接続出来ない時のために、必要に応じてバックアップ用としてローカルに保持してあるMDBも参照するようにしようか」

僕が細かく実装してあった myDBConnect クラスはSQLServer専用クラスである。
中身には SQLClient名前空間のクラスやらメソッドやらプロパティやらがビッシリなのだ。

MDBも見れるようにするには、中身を全てODBCに変更してやる必要がある。
そうして作るクラス myODBCConnect は、myDBConnect とうまいこと併用しなければならない。
(ちなみに、SQLServerとMDBへの切り替えをmyDBConnectクラスで実装しようとするやつはプログラマ失格だと思う)
例えばこんな感じ。

Dim DBCon as new myDBConnect(Me._ConnectionString)
Dim ODBCCon as myODBCConnect

If DBCon.IsConnect() Then
DBCon.ExecuteSQL(Me.sqlquery)
Else
DBCon.dispose()
ODBCCon = new myODBCConnect(Me._ODBCConnectionString)

If ODBCCon.IsConnect() Then
ODBCCon.ExecuteSQL(Me.sqlquery)
End If
End If

僕「上司!MDBにも対応してやったぞ!」
上司「ご苦労!」

話がここで終われば万々歳。
しかしながら、仕様というのは変更が重なるものだし、要求というのは日々噴出してくるものだ。

例えばここで

上司「すまーん、Oracleも付け足してくれ」

なんていわれたら、これはもうたまらん。
クラスは一つ増やすだけだけど、コードが非常に見にくくなる。
せいぜい出来ることといったら

Select True
Case SQLDBCon.Isconnect

Case MDBCon.Isconnect

Case OracleCon.Isconnect

End Select

ぐらいのものだけど、処理効率としてはあんまりよろしくない。

そこでインターフェイスを使ったコーディングがモノを言う。
インターフェイスというと、クラスに対して共通のメソッドを用意できちゃうぐらいの認識しか持たれてないので、イマイチ何に使うのかよくわからないことが多い。というか僕はメリットがまったくわからなかったクチだ。だってImplementsだけして実装は各クラスの中で、って、なんかまだるこっしい。

しかしながら、『そのインターフェイスを持つクラスなら何でも実体を代入することが出来る』という用法に気付いたとき、インターフェイスの強力さが垣間見えた。

つまり、上記の例で言うとこういうことだ。

Dim IDB as IDBCon ←インターフェイスをフィールドとして持つ

IDB = new SQLDBCon(...

If IDB.Isconnect = false Then
IDB = new MDBCon(...
End If

If IDB.Isconnect = false Then
IDB = new OracleDBCon(...
End If

IDB.ExecuteQuery(Me.sqlquery)

この場合、
SQLDBConクラス、MDBConクラス、OracleDBConクラスは、IDBConインターフェイスを実装している必要がある。
即ち、各クラスはIsconnect関数とExecuteQuery関数を既に実装しているわけだ。
その前提さえあれば、インターフェイスに対してクラスの実体を代入することが出来、とても高い柔軟性が得られる。

例えばここで上司が

「水上くん、すまん、Postgreにも対応しなきゃならん可能性がある。いつでも対応できるように考えておいてくれ。」

なんていわれたら、最初だとIf文見直しから始めないといけなかったけれど、
インターフェイスを用いてコーディングを行った場合、クラスだけ作っておけば後からいつでも追加することが出来るってわけだ。

インターフェイスって便利ですね。

さらにさらに、Gang of Fourのデザインパターンを組み込むと、コーディングはさらにこうなる。

Dim IDB as IDBCon
IDB = new Factory.GetAdaptableDB()

IDB.ExecuteSQL(Me.sqlquery)

すっげ簡単!
ちなみにこれ、何かというとFactoryMethod。
いや、AbstractFactoryなのか?まだその辺よく区別ついてないけど、とにかく必要に応じてクラスを生成することの出来るもの。
Factory.GetAdaptableDB関数の中で、接続することの出来るDBを見つけ出す処理を走らせ、最後に

Return new SQLDBConnection(ConString)
だか
Return new OracleDBConnection(ConString)
だかなんだか知らないけど、IDBインターフェイスを備えたクラスを戻り値にしてやる。
すると、使用する側から見れば、どのDBを使っているのか『意識することなく』、DBを利用出来るってわけです。
クラスを生成する責務を担当したクラスがFactoryクラスだから、新しいDBを追加したりする際にはFactoryクラスだけをいじってあげればいい。

便利だなあああああああああああ!!!!!!!!!

ちなみに余談だが、プログラミングのインターフェイスはこのように概念的かつ職業的でわかりにくいけど、現実世界のものにたとえるとインターフェイスってものが途端にわかりやすくなる。
現代の発明品の中で、最も優れたインターフェイスを持つものは何か?という問いかけに対しては、『車』が上げられる。
車の種類はアホほどあるが、どんな車にも、
・燃料を補給
・ハンドルを回せば向きが変わる
・アクセルを踏めば走り出す
・ブレーキを踏むと止まる
と言う『機能』があり、全ての車はこの機能を搭載する。

だから、教習所でこの機能の使い方を学ぶだけで、(乗用車なら)どんな車でも運転できる資格を得ることが出来るようになる。
車の定義が種類によってバラバラなら、乗りたい車の数だけ教習所へ通う必要があったんだろう。けど僕らがそうする必要がないのは、車が明確なインターフェイスを持つから。

これをヒントにすれば、色んな物事を俯瞰して考えることが出来るようになり、とってもオトク。