|
データ指向の話 第一章「基礎編」 - やまざき@BinaryTechnology
「デスマーチと戦う武蔵流プログラマ やまざき のページ」 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
やまざきが書いた本
やまざきが寄稿した本 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
まず、データ指向の目指すところは「わかりやすいこと」です。 特にコード上では「可読性」を重視します。 すべてにおいてこれが優先されます。 ● データ指向という言葉 「データ指向」という言葉ですが、聞いたことはない と思いますが、 それもそのはずで、わたしが勝手に名付けた言葉ですから、 心配しないでください。 もし、この言葉を「以前に聞いたことがある」という方がいましたら、 それは、おそらく別の概念と思われます。気を付けてください。 その場合は「データ主眼設計」とか、「スコープ指向設計」などと、読み替えていただいても結構です。 もしくは、「コンポーネント指向」という言葉が近い概念かもしれません。 基本的な考え方は「データを大切にしよう!」とか 「機能ではなく、データに着目して考えよう!」というものです。 この概念による効果は「可読性の向上」や「わかりやすさ」「保守のしやすさ」だと思っています。 おそらく、プログラマの方であれば、メリットのある話だと思います。 難しい話ではないので、気楽に読んでください。 ● オブジェクト指向との違い オブジェクト指向の概念は、主に「値(変数)と機能(関数)を 部品(オブジェクト)としてまとめて切り出すこと」「どちらかといえば機能を重視して切り出すこと」を薦めている概念だと思います。 データ指向の概念では、主に「値(変数)を優先的に切り出すこと」を薦めます。 機能(関数)の切り出しの優先度はその次になります。 データ指向はオブジェクト指向へのアプローチの1つの方法(概念)である と考えていただいても、問題ないと思います。 一般的なプログラム開発では、機能や振る舞い「何をするのか?」に着目して 切り出し/分割/実装 して行きますが、 データ指向では、まずデータ(変数)「何があるのか?」に着目し 切り出し/分割/実装して行きます。 実際にコードを書いてみるとわかると思いますが、 このほうが、切り出しやすく、実装しやすすく、 さらに「わかりやすい」のです。
データを切り出すと言っても、難しく考えないで下さい。 下の C言語での例を見れば簡単に理解していただけると思います。 この↑コードには変数(データ) a と b があります。 しかし、a と b は同時に生成される必要も無いのに 同時にというか、まとめて生成されています。 このデータの生成と破棄に着目して書き直すと。 と、こうなります。実行結果はまったく同じです。 どうでしょうか? 言いたい事がわかりますか? ● スコープ そうです、C言語では「スコープ '{', '}'」のことです。難しく言うと「データの隠蔽」です。 簡単に言うと「変なアクセスからデータを守ること」です。 これがデータ指向の考え方の基本になります。C言語では、単純にスコープを多用するだけで データ指向のメリットが発揮されます。 上記の場合、変数(データ) a にアクセスできる行は、極端に減っています。 a に「アクセス できない」ということは、 a に「バグを入れることが できない」 といえるのです。逆に、 a に「アクセス できる」ということは a に「バグを入れることが できる」ともいえます。 これは、「データの寿命が短ければ、それだけバグりにくい」 という考えかたです。 コードは長くなりますが、保守のしやすさや、わかりやすさ、可読性が良くなるのです。
データ指向では、データの隠蔽を最も重視しています。 データの隠蔽の仕方にもいろいろあり、 簡単なところでは変数や関数の名前の付け方による隠蔽も可能です。 この方法は、実際に物理的に(コンパイラの言語仕様などで)隠蔽されていなくても 各自で命名規則を設けることで 理論的に「隠蔽されているかのように使用する」 ということを示しています。 命名規則の話は言語仕様によって異なってきますが、 一般に言語仕様とは無関係である変数の名前や 関数の名前を工夫するだけでも 効果が発揮されます。 極端な例をあげると「わかりやすい名前を付けよう」と いう簡単な規則も「データ指向」になるのです。 わかりやすい名前は、ハンガリー(ハンガリアン)記法より重要だと思います。 ハンガリー記法は、主に「型の情報を変数名に入れよう」という記述方法だと私は解釈していますが、 実際には、型よりも重要な情報があると思うのです。 たとえば、グローバルなのか?、ワークなのか?、引数なのか?、リファレンスなのか?、 ポインタなのか?、配列なのか?、固定値なのか?、などなど。 データ指向では、こういったアクセス方法に関する情報を重視します。 「変数名には、型より重要な情報があり、それを優先して記述すべき」と思います。 特にC言語などでは、名前は短い方が良いとされていますが、そんなことはありません。 わかりにくくなるのであれば、短くしてはいけません。 確かに、3行程度で消えて行くワーク用の変数に対して、 20桁もある名前を付けることはないと思います。 しかし、より広い範囲で(グローバルに)アクセスされる変数に対しては 慎重に名前を選ぶべきです。 重複しづらい命名規則や、アクセス範囲を定めた名前をつけることで、 隠蔽の効果を発揮させることができるのです。 たとえば、C言語にて このような短い1文字の変数名を広い範囲で使用するよりも、 意味のある名前をつけたほうが、わかりやすいですし、 誤って同じ名前を使用する確率が下がり、 バグが入りにくくなるのです。 ここで取り上げている多くのサンプルコードや、C言語系の入門書などでは、 変数名の短いモノが多いです。 しかし、これはサンプルコードとして「特別に短く書いている」と認識し、 一般のコードにそのまま適応するのは避けてください。 この辺りの誤解のないようにお願いします。
データのアクセス範囲の例をC言語で示します。 まず、C言語でのデータの種類は 大きく分けて この4種類があります。 特に呼び方が統一されて決まっているわけではないのですが、 あえて呼び方を決めるのであれば、 となるでしょうか。 アクセスできる範囲は a > b > c > d の順に広いので、 データ指向では、できるだけアクセスできる範囲の少ない ローカル変数 d を多く使うことを推奨します。 「できるだけ、アクセス範囲の狭いモノ」 「できるだけ、アクセス権限の厳しいモノ」 を使うように心がけてください。 また、できるだけグローバル変数 a は使わないで下さい。 いや、できるだけ では止めずに「絶対使わない」という気持ちで望んで下さい。 「グローバル変数撲滅運動」をおこすのも良い案かもしれません。(^^; このような優先順位をつけることで、データの寿命が短くなり、 バグの入る余地が少なくなります。 その根拠は、「データの寿命が長いとそれだけアクセスされる確率が高くなり、 バグの入る確率も高くなる」という考え方からです。 またその他のメリットとして、一度に覚えなければならないデータの数が減ります。 たとえば と、 では、 覚える必要のある(気を配る対象となる)データの数が極端に違います。 これは、コードが長くなれば長くなるほど より大きく 深刻な問題になるので 1度に7個以上のモノは覚えられないと言われている人間の脳には 大変、有効であるといえます。 さらに、データだけではなく、関数名やメソッド名についても、 より「アクセス制限の厳しいモノ」を「使用範囲の狭い場所」 にて使用することで、同様の効果がえられます。 しかしながら、現実の問題として、関数などに対してアクセス制限の概念のある言語は数が少なく、 オブジェクト指向系の言語(C++やJavaなど)から選択せざるを得ないのは 辛いところです。 ともかく、対象がデータであれ、関数(メソッド)であれ、 気を配る対象が減れば、確実に生産性も保守性も上げることができます。
データ指向の前提である「わかりやすさ」について C言語のコードを用いて実例をあげてみます。 なお、使用前のコードは某C言語の演習問題の回答例から抜粋しました。 他意はありませんのでご了承下さい。 データ指向・使用前 データ指向・使用後 (1) 暗黙の宣言はわかりにくく、バグが入りやすいので避ける。 さらに、main() の宣言は void ではなく int が妥当。 (2) わかりやすい変数名を付ける。 特に 文字列 xxx_str なのか?、配列 xxx_tbl なのか?、ポインタ xxx_ptr なのか? が重要。 ちなみに、ポインタの場合は char * abc_ptr = "ABCDEFG" ; などとする。 (3) 速度より、わかりやすさを重視し、あらかじめ長さを求める。 速度が遅くなるかどうかはコンパイラしだいなので、 コーディング時はできるだけわかりやすさを優先する。 なお、変数は宣言時に必ず初期化する。 (4) while 文はわかりにくいので使用せずに、for 文を使う。 さらに、条件文には、ちゃんと条件を書く。 *p では、なんの事だかさっぱり分からない。 なお、ポインタはわかりにくいので使わない。 (5) 1行でもスコープは必ず書く。 ループが1行の場合スコープを省略する人もいるが、 コードに変更が入りバグを作りこむ場合もあるので、 面倒でもスコープを書く癖をつけたほうがよい。 (6) ちゃんと return を返す(VC++では無いとエラーになる)。 (7) 全体的にスペースを効果的に用いてより見やすさを追求する。 なお、タブは使わない。 その理由は、タブを使うと環境によって表示のされ方が変ってしまうことがあるが、 スペースであれば大きく変わってしまうことはないため。 さらにできることなら適切な位置に適切なコメントを入れる。 また、コメントは特に「こう書くべき」という規則を設けないほうが良い。 理由は、人の考え方は常に変わるものなので、 形式にこだわって本来書くべきモノが書けなくなるのでは本末転倒であるから。 まだまだ細かいところはたくさんあるのですが、 これだけでも かなり保守が楽になると思います。 データ指向とは直接関係無いのですが、わかりやすさ、保守性、可読性の良いコードを書く という癖をつけるところにデータ指向の原点があると思うのです。
ここでは、データが生成されることを「生まれる」、 データが破棄されることを「死ぬ」と表現しています。 生まれる場所(宣言する場所)については以前にも出てきましたが、 もう一度 おさらいすると。 「できるだけ、アクセス制限の多いところ。」 「できるだけ、アクセス範囲の狭いところ。」 となります。 さらに「データの寿命は短い方が良い」と言いましたが、 「なにがなんでもとにかく早く殺せ」というのではなく、 「ちゃんと、生まれたところへ返しましょう。」 が正しいデータ指向になります。 例をあげると これ↑はちょっと変ですね。(a) のところで p はアクセスできなくなっています。 正確には、アクセスはできるが アクセスできる状態ではなくなっています。 これは、「データの寿命は短い方が良い」にはあっていますが、 「わかりやすさ、保守のしやすさ」がダメです。 これでは「健康のためなら死んでも良い」というのと一緒です。 そうではなくて、ちゃんとスコープのレベルを合わせて もしくは となります。 また、C++には「コンストラクタ/デストラクタ」という とても便利な機能が あるので、それをうまく利用すると データの生成/破棄がとても楽になります。 データ指向にとって データの生成/破棄は、 C言語でのスコープと同じくらい重要ともいえる とても重要な要素なので、 これらの処理が楽になる というだけで、 C++や他のオブジェクト指向言語を使うメリットがあると思います。 コンストラクタ/デストラクタを積極的に利用しましょう。 C言語の malloc()/free() をC++のコンストラクタ/デストラクタを使って 書くとこのような↓感じになります。参考まで。
C言語で変数というと、 と記述しただけで変数(入れ物) a として用意されます。 しかし、中身のデータは「不定」です。 不定というのは、中の値が意味を持たないのであって、 実際には「ゴミ」が入っているわけです。 このゴミが「たまたまゼロだったから動いていた」とか、 「printf() ; 文を追加/削除したら正しく動かなくなった」 などという話をよく聞きますが、諸悪の根源はこの空の変数にあります。 データ指向では、データの無い入れ物だけの状態を「バグの元」だと 考え、その存在を「悪」であるとしています。 最近のほとんどの言語では、この「悪」な状態を簡単に作ることができてしまい、 意識していないと、どんどん「悪の世界」に引き込まれていきます。(^^; ですから、データ指向の世界では を推奨します。いや、推奨ではなく、必須とします。^^; こんな↑コードを書いて、バグを作った人も多いことでしょう。 これは、こう↓書くか または、こう↓書くことで、バグは除去できます。 しかし、この変数宣言時の初期化を強制した言語が無いのはとても残念です。 オブジェクト指向な言語、C++でも としただけでは、変数(オブジェクト) b の中にデータが入っているのかいないのか さっぱりわかりません。 この場合、必ず class Boo のコンストラクタで、データを生成(初期化)して 「データの存在しない変数は無い」と思えるように設計/実装 を心がけましょう。 こうすることで、常に 「変数=データ」の式が成り立つようになり、 余計な事を考えなくてもよくなり、バグが減り、工数も減ることにつながります。 少し難しい言葉で書くと「インスタンスの生成と破棄を、ライフタイムに一致させる」 ということになります。データ指向ではこれを重視します。 余談ですが、Windows系のクラスライブラリ(MF○)では、このような思想はなく、 ほとんどのクラスが、定義とは別に初期化のメソッド Create() とか、 解放メソッド Delete() などを用意しています。 この設計思想はまずい(バグの元)と思います。 メソッドを増やしたほうがコードの柔軟性が上がるのは事実だとは思いますが、 それは、実装者(コーダー)に対して不親切だと思います。 「どう使えばよいのか?」「適切なコードはなにか?」という判断が難しくなり、 不必要な時間と、バグの要因を増やしているように思えます。 データ指向のスタンスではお薦めできません。 このような設計思想に染まらないように注意しましょう。^^;
変数の使いまわしは「悪」です。 このことは、データ指向の「データの生成と破棄を明確にする」 ということに反しています。 「変数=データ」とすべきなので データの意味が変ったら、ちゃんと変数を破棄して「新しい変数を生成すべき」です。 たとえば、よく見かける使いまわしの例(C言語) ↑こうではなく、 こんな感じに書きます(これもC言語^^;)。 または、こう↓書いてもよいでしょう。^^; 理由は上の変数 i と 下の変数 i は別のモノで、データの意味が違う(別のモノをカウントしている)からです。 こう書くと、見栄えはわるい(C言語の仕様がデータ指向にあっていないとも言える) のですが、保守は楽になります。 例えば、下の i のループを他の場所に移動した場合、 「i が宣言されていません!」なんてことには なりません。 気になる実行速度も、ちゃんとコンパイラが最適化してくれますから、同じ(はず)です。 むしろ、速度が変ってしまった場合、コンパイラの能力が低いので コンパイラを変えましょう。(^^;
コーディング時に 注意すべきところは、 スコープによるインデント(字下げ)の深さです。 インデントが深いとそれだけアクセスできるデータが増えていることになります。 さらに、どんどん見難くなりますし、あまり好ましい状態ではありません。 インデントの深いところは、データを隠蔽すべきところです。 あまり深くならないように、データを分けましょう。 C言語ではファイルを別に分け、C++では class を別に分けるべきでしょう。 例えば ↑こういうのは、 と、このように分けます。 この時注意すべきところは、機能で分けるのでは無く、あくまでも 「データの生成/破棄の単位(この場合は int c )に 着目して分ける」 というところです。 ● if 文による深いインデント スコープとは別に、if 文を複数組み合わせると、 やはりインデントが深くなる傾向にあります。 これを解消する1つのテクニックをお教えしましょう。 ただし、あくまでも「こう書ける」というレベルでとどめておいてください。 「こう書くよう」推奨しているわけではありませんので念のため。 一般に、if 文のインデント(階層の深さ)はこのように↑なります。 これを解消するためにここでは goto 文を使います。 return 文や break 文でも良いのですが、意味も無く関数や do-while(false) 文を増やすよりは goto 文の方が良いかと思います。 goto 文は、一般に構造化設計では使用禁止とされますが、 正しく使えばむしろ良い効果を発揮します。 見た目にすっきりしているので、goto 文の悪の要素は消えていると思います。 本来であれば、break 文を使いたいのですが、C/C++の言語仕様ではうまく書けません。 このあたり、もう少し、C言語やC++の言語仕様も融通がきくと良いのに・・・などと考えてしまいます。 こればかりはそう簡単に変わらないと思いますが、近い将来、 安全に(可読性が悪くならないで)このような書き方のできる言語が現れると嬉しいのですけど。 「break 文 強化運動」とか(またそれか^^;)ね。
引数には「アドレス渡し」と「コピー渡し」と「リファレンス渡し」の 3種類の渡し方があります。 まずは、この3種類の違いをしっかり理解して、自分のモノにしましょう。 データ指向では「リファレンス渡し」を推奨します。 C言語には「リファレンス渡し」の概念はないのですが、 C++にはしっかり取り入れられています。 C言語では、仕方が無いので「コピー渡し」を使いましょう。 「リファレンス渡し」を推奨する理由をについて述べる前に、 まずは各々の引数の特徴について簡単に見てみましょう。 ●アドレス渡し まず アドレス渡し というのは、C言語ではかなり浸透した概念です。 ちゃんと意識していないと、いつのまにか使っていたりします。 しかし、データ指向の根本的思想である「データに着目」して考えた場合、 「データが存在するのかしないのか不明なのにアドレスは存在する」 という状態は極めて「悪」なモノなのです。 データがアドレスで渡ってきた場合、 「アドレスの示す先にデータが必ず存在するという前提」 でコードを書きます。 しかし、アドレスを渡した元で、そんなことはすっかり忘れてしまい 渡したデータをさっさと破棄して「バグる」というケースはよくおこります。 特に「データの生成〜破棄の期間は短い方が良い」として、 さっさとデータを破棄する癖が付いてくると、よくおこるようになったりします。(^^; このあたりの話は「ポインタ有害論」にもつながるのですが、 データの流れに着目する意味で「アドレス渡しは悪」です。 アドレス渡し にはもう一つ便利な(?)使い方があります。 それは、データを返すコードに使われます。 例えば、こんな↓感じです。 これは、最初 buff[128] の中はゴミだらけだし、アドレス渡しだし、 128 バイトというデータのサイズ情報も渡らないし… データ指向とまで言わなくても、一般的なプログラミングとしても 「悪」なコードです。 そこで、C言語ではちょっと書けないのですが C++ではこんな↓感じで書きます。 こうすればアドレス渡しも回避できますし 初期化や、データサイズの問題もクリアされます。 アドレス渡しにしない方法はいろいろあるものです。 そんなわけで、アドレス渡しは止めましょう。 ●コピー渡し C言語やC++では、引数は一般にコピー渡しが使われます。 特に意識しない場合はコピー渡しになっているということです。 「コピー渡し」と「リファレンス渡し」の違いですが、 コピー渡し は、文字通りコピーを作成して、引数に乗せます。 データ指向の概念から見て 特に大きな問題はありません。 ただ、コピーする必要も無いのにコピーしてしまう場合があるので コピーなのか?オリジナルなのか?、意識する必要があります。 一般的に参照のみのデータをコピーで渡すのは無駄があり、 これは渡すデータが大きくなればなるほど、 (特に int 型などでなく、class などの大きな型の場合) コピーを作る無駄も大きくなります。 賢いコンパイラが最適化してくれればコピーの無駄もなくなるでしょうが、 C++ではコピーコンストラクタとかも走りますので、 参照のみの引数では「リファレンス渡し」をお薦めします。 「コピー渡し」は「アドレス渡し」ほど「悪」ではないので 使用禁止とまではなりません。 リファレンス渡しのできないC言語などでは、コピー渡しを使いましょう。 ●リファレンス渡し 「リファレンス渡し」では、コピーは作らずに データの入っている変数そのものを渡します。 変数を渡すというより「変数はここにあるので、これを使ってください」というイメージです。 コピーを作るかどうかは、関数の呼び出しではなく 新しいデータが生まれる時に決定するモノだと思います。 「コピーは意識して作るべきである」と思います。 「リファレンス渡し」には、1つだけ「上書きされる危険性」があります。 これは「const コンスト」識別子をつけることで回避できます。 特に参照のみのデータを引数に渡す場合は「コンストリファレンスは必須」 と言ってよいでしょう。 C言語になれている人は「コピー渡し」になれてしまっているので、 急に「リファレンス渡し」にするのはなかなか難しいでしょう。 その場合は、無理に変更してバグを作り込む可能性もあるので、 無理をせず、徐々に変えていけば良いと思います。
最後に、データ指向の具体的な適応例をコードで見てみましょう。 ここは、この章の山場です。 ここをなんとかクリアすれば、私の言いたい「データ指向」について 理解できているはずです。 一息入れて、気合を入れ直して、読破しましょう。 まずは、「面積を求めるコード」に対して、復習の意味をこめて、 「何も考えていないコードから、オブジェクト指向が適応されるまで」 (obj-1) なにも考えていないコード (obj-2) 変数による数値の意味付け (obj-3) 関数の概念を追加 (obj-4) 構造体の概念を追加 (obj-5) 情報隠蔽なしクラス (obj-6) 情報隠蔽ありクラス の過程を段階的に見てみましょう。 (obj-1) なにも考えていないコード 計算するだけなので、答えは出ますが、 3*2のどっちが「縦」で、どっちが「横」なのかまったく不明です。 保守できるような状態ではなく 可読性の悪い状態と言えます。 (obj-2) 変数による数値の意味付け 変数の概念を追加することで、数値に対して意味付けができます。 このレベルまで書かれればある程度の保守は可能になります。 しかし、変数の数が多くなる傾向は避けられません。 (obj-3) 関数の概念を追加 一般に構造化設計と言われる概念である、プロシージャ(関数、処理、機能)を 切り出して1つにまとめます。 変数の数は変わりません。 計算式に意味が付いただけで、あまり大きなメリットは感じられません。 (obj-4) 構造体の概念を追加 「構造体」を作り、データを構造化します。 同時に、関数(処理)も構造体に合わせているので、 このあたりにオブジェクト指向の前段階のような傾向を感じます。 しかし、完全に1つの概念としてまとまっているわけではありません。 変数の数が減って、わかりやすくなっています。 ただ、構造体と関数の関連付け(まとまり)はまだ弱いです。 (obj-5) 情報隠蔽なしクラス オブジェクト指向の導入します。カプセル化を行います。 変数(データ)と関数(処理)がクラスという概念で強く結ばれます。 まだ、rect_b.m_width, rect_b.m_height に直接アクセスできてしまうので、 バグの入る予知があり危険です。まだ、安全性が低いとも言えます。 (obj-6) 情報隠蔽ありクラス さらに、情報隠蔽を行います。 rect_b.m_width, rect_b.m_height に直接アクセスできないので、 隠蔽度が上がり、安全性が上がりました。 現状では、ここまですればオブジェクト指向に対応したと言えると思います。 ここまでの解説で、オブジェクト指向とはどういうコードを書くことをいうのか 理解していただけたと思います。 (obj-1) のコードに比べて、(obj-6) のコードはかなり行数が増えました。 しかし、データ抽象化、カプセル化、情報隠蔽され、安全性、保守性、再利用性などが上がり、 バグの入りにくいコードになっています。 小さなプログラムを作る時は、コードが増えるだけで、 あまりメリットが見えてきませんが、 大きなプログラムを作る時に、この情報隠蔽による安全性が大きな威力を発揮します。 これがオブジェクト指向の大きなメリットであると思います。 ● データ指向を適応 ここからは「具体的にデータ指向をコードに適応するとどうなるか?」を示します。 データ指向は比較的コーディング初期の段階から適応できます。 上記、(obj-2) の状態にデータ指向を適応すると以下のようになります。 (data-2) (obj-2)にデータ指向を適応 まずは、スコープを用いてデータの寿命を制限します。 具体的には、面積 a をもとめるのに、面積 b の情報は必要無いので、 それぞれをスコープで囲います。 アクセス範囲を狭く制限することで、バグが入りにくくなります。 このコードをみると、どこをクラスにすれば良いのか、わりと簡単に発見できます。 データに着目してまとめることで、それに処理がついてくるかたちでクラスの候補が見えてきます。 データ指向は「オブジェクト指向への通過点にある」とか、 「オブジェクト指向へのアプローチの1つとしてデータ指向がある」 と考えていただいて問題無いと思います。 しかし、オブジェクト指向を適応した後であっても さらにデータ指向を適応できます。 例えば、(obj-6) の状態で適応すると以下のようになります。 (data-6) (obj-6)にデータ指向を適応 こうすることで、更なるオブジェクトの発見につながる可能性も見えてくるわけです。 データ指向をすすめることでデータがクラスに行き着く場合は多いですし、 クラスにまとめることが容易になるとも思います。 しかし、すべてのデータがクラスに行き着くか?というとそうではなくて クラスにするまでもないデータはたくさんあると思います。 そして、データ指向も、オブジェクト指向と同じように 設計の前段階から適応できるのです。 わりと簡単に適応できるので、頭の中で、 「このデータとこのデータではどっちが先に生まれるか?」とか、 「全体を通して使うものだから、さっさとクラス化してしまおう」とか、 考えをすすめて行くことが可能です。 複数のデータがからんでくると、紙に書き始めたほうが良いですが、 多くは、頭の中と、コーディング上で解決できます。 わりと気軽に適応できます。 ● 仕様変更にともなう影響 次に、データ指向を適応したコードに対して仕様変更を行うとどうなるのか? どのような影響があるのか?見てみましょう。 試しに「総面積(all_area) をもとめる仕様」を追加します。 まずは、クラス化する前のケース((data-2)の状態から)は以下のようになります。 (update-2) (data-2)に対して仕様変更 次に、クラス化した後のケース((data-6)の状態から)は以下のようになります。 (update-6) (data-6)に対して仕様変更 と、こうなります。 基本的にスコープはそのままで、大きく崩れることはありません。 逆に、仕様変更などでコードが大きく崩れるような場合があるとすると、 それはまだまだデータ指向の適応が薄いと思われます。
データ指向は、オブジェクト指向よりも簡単 というか、 お手軽なので、それほど深く考えなくても気楽に適応できたり、 他人が書いた、なんの考慮もされていないコードに対しても ある程度有効です。 オブジェクト指向を適応するには、全体を見通さないと難しいですが、 データ指向であれば、その場の思いつきでポンポン適応できますから 適時気が付いたところから対応できるのはやはり楽です。 オブジェクト指向を適応するには、やはりある程度の(というか、かなりの)経験を 前提としているようなところがありますが、 クラスの設計とか、抽象化とか、できあがったシステムに対して 「ここはクラスだね」とか、後からなら いくらでも言えると 思うのです。(コロンブスの卵というか・・・違うか^^; ) ところが、実際に新しいシステムを設計/実装してみるとわかると思うのですが、 考えもしなかった(予想もできなかった)概念や仕様がゴロゴロ出てくるのです。 この辺は「経験が必要だ」と言ってしまえばそれまでですが、 どんなに経験を積んでいても、やはり新しいシステムを組むと 新しい概念に遭遇すると思いますし、 すべての人がすべての経験をすることなんて 物理的にも できるわけが無い とも思うのです。 オブジェクト指向の概念はすばらしいとは思っているのですが、 一方で、適応できなければ「絵に描いた餅」だとも思っていまして、 そのあたりの思いが「データ指向」に出てきているような気もします。 どうでしょうか?、 データ指向のメリット というか雰囲気を(大雑把にでも)つかんでいただけたでしょうか?。 これで、基本的な概念はすべてお話したつもりです。 「変数や、型、スコープなどの概念の重要さ」について 再認識していただければ この章の目的は達成できています。 つぎは、この概念を少し抽象的に広げて適応するとどうなるか見てみたいと思います。 ただ、ここまでの内容が「難しい」とか「さっぱり理解できない」と感じた方は無理をせずに、 もう一度この章を読み直して見てください。 では、第二章に進みましょう。 データ指向の話 第二章「応用編」へつづく。 ご意見、ご質問など、掲示板の方で常に受け付けています。 last update 2003/02/06 since 1998/07/14 |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Copyright(c) 1998-2006. YAMAZAKI Satoshi. All rights reserved. since 1997/12/15 |
● このページのURLをメールで送る(友人・知人に教えてあげる) ● このページを「お気に入り」に追加する(忘れないように…) ● お手紙はこちら↓。仕事の話は大歓迎です。(忙しくて返信できなかったらごめんなさい。) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||