先週に続きましてオブジェクト指向再考ということで特にオブジェクト指向に毒された方を対象に現実的な観点でプログラムできるように、プログラマとして社会復帰できるように、ヒントを出したいと思います(もちろん回復するかどうかは本人次第です)。
今週からはメッセージについて話たいと思います。世の中には、
メソッド(メッセージ)>>どうしようもない壁>>関数
と思っている方がいらっしゃるようですが、今後数回に分けて、この『どうしようもない壁』というのはオブジェクト指向病特有の幻覚であるということを示したいと思います。まぁ、厄介なことに患者さんには明確に壁が見えているのでなんとも言えないのですが、もし少しでも『これは幻覚かも?』と思った方はこの連載が助けになるかもしれません。ちなみに『この壁を感じれないやつはプログラマとして終わっている』とお思いの方はお帰り頂いて構いませんし、反論のコメントを書き込んで頂いても構いません。
前回の最後に示しましたが、オブジェクト指向のキーファクターとしてメッセージがあります。この考え方(パラダイム)はそれはそれで素晴らしいものです。分かり切った例をあげますと、マウスの入力(クリック)がメッセージとしてOSに伝わり、イベントハンドラ(コールバック関数)に制御が引き渡されます。当たり前のようですがこの仕組みはメッセージパラダイムを具現化したものになります。もしメッセージを使わなかったら、例えば定期的にマウスの位置を読み込み、クリックされたどうかを確認することになります。考えただけでも厄介ですよね。GUIプログラムがイベント駆動型と言われる所以ですね。
さて、ここでのキーポイントは、『世の中の事象は全てイベント駆動(メッセージ)で記述するのが良いことか?』ということになります。例えば、以下のプログラムを考えましょう。
ユーザがスタートボタンをクリックしたら画面に"Hello"と表示する。
間違いなく、『ユーザがスタートボタンをクリックしたら』、というところはイベント駆動と相性がいいですね。では次の
『画面に"Hello"と表示する。』・・・・・(A)
というのはどうでしょうか?この部分はイベント駆動またはメッセージで記述できるでしょうか?
よくオブジェクト指向の教科書に出てくるのですが、
『画面オブジェクトに、引数に"Hello"を指定して表示依頼のメッセージを送る。』・・・・・(B)
というのを見受けます。最初に指摘しますと(B)は(A)を劣化させたものだと言えます。
ポイントは(A)は手続き指向で書かれて、(B)はオブジェクト指向(メッセージ指向)で書かれています。そして重要な点ですが、この場合、(A)はプログラムの仕様(本当にやりたいこと)を表していて(B)はプログラムそのそのものの説明を行っている点ということになります。つまり、(B)は以下のようなコードの説明を行っているということになります。
label.setText("Hello");
ここで画面オブジェクトというのがlabelになり、setTextが表示依頼メッセージで"Hello"が表示対象の引数ということになります。
つまり(B)は上記のコードの説明を行っていることになり、(A)は上記のコードの意図を表しています。
もし上記のコードにコメントを付与する場合、(A)、(B)どちらが良いでしょうか?
label.setText("Hello"); // 画面に"Hello"と表示する。・・・・・(A)
label.setText("Hello"); // 画面オブジェクトに、引数に"Hello"を指定して表示依頼のメッセージを送る。・・・・・(B)
(B)の方がよいという考え方の人に質問したいのですが、ラベルオブジェクトに値をセットする方法にはプロパティを使うというものもあります。つまり以下のコードもありえます。
label.Text = "Hello";
この場合、(A)、(B)どちらのコメントの方が適切でしょうか?
label.Text = "Hello"; // 画面に"Hello"と表示する。・・・・・(A)
label.Text = "Hello"; // 画面オブジェクトに、引数に"Hello"を指定して表示依頼のメッセージを送る。・・・・・(B)
それとも以下のようにコメントするのでしょうか?
label.Text = "Hello"; // ラベルプロパティに"Hello"をセットする。・・・・・(C)
もっとも、(C)のような発想もオブジェクト指向から離れたと言えるでしょう。
さて、ある程度経験のあるエンジニアなら大なり小なりこのようなジレンマを抱えたことがあるかと思います。つまりメソッドの中身を書こうとしたときに『どうもオブジェクト指向していないな・・・』と感じることがあったかもしれません。しかしよく考えてみれば分かりますが、メッセージ指向というのはある種の手続きの上っ面(呼び出し方法)についてパラダイムであり中身をどうするかは別問題ということに気付くかと思います。
ここで重要なことは、
メッセージというのはプログラミングパラダイムの一つであり、メッセージで表現した方がよいもの(例えばイベント)もあれば、そうでないもの(手続き指向のもの)があるということで、プログラマは適宜適切なパラダイムを選択してプログラムを行えばよいです。多くのプログラマは、プログラミングパラダイムについて
オブジェクト指向(メッセージ指向)> 手続き指向
と考えているかもしれませんが、実はそれぞれ適材適所があり適宜使用すればよいということになります。つまりマルチパラダイムですね。さてオブジェクト指向言語しか知らない方は実は手続き指向という発想がないかもしれません。何かをステップバイステップで処理をするという発想が手続き指向になります。特段難しいとは思えないですが、もしピンとこない方がいらっしゃいましたらコメントを下さい。
イベント処理を手続き指向で考えるのは不適切ですし、能動的に画面に何か表示したいと思った時にいちいちメッセージ云々を考えるのも不適切ということになります。そう考えると以下の2つの記述方法のどちらかが適切か理解できるかと思います。
z = 3 * x * y + 4 * x + 6 * y + 2;
z = 3.multiply(x).multiply(y).add(4.multiply(x)).add(6.multiply(x)).add(2);
もう迷う必要はなく上の方が適切だと理解できるかと思います。数式も一つのパラダイム(というか表現方法の一種)だと理解すれば無用なパラドックスに悩まされる必要もなくなります。
次回は、メソッドと関数についてもう少し突っ込んで話したいと思います。
2016-03-23 15:04:28
素晴らしい内容だと思います。
わかってる人(オブジェクト指向に疑問をもちつつある人)には、
・上手い例
・上手な説明
だと思います。
しかし、洗脳を解くにはには弱いし、難しいかも?
よろしかったら一つ質問させて欲しいのですが。
文字数で処理する関数、length関数、substring関数が存在する世界で、
byte数で処理する同様の関数を作成することになるとしたら、
どのような名前を付けますか?
私ならlengthB関数、substringB関数。
しかし洗脳されている人たちはほぼ例外なく、
byteLength関数、byteSubstring関数
ときます。
(byteを略すor略さないは些末な話で趣旨じゃないです。
修飾を前にするor後にするが趣旨です。)
私の解釈では、
・現実的な使い勝手を優先した命名
・オブジェクト指向的な(メッセージライクな、かっこいい)命名
の違いだと思うのですが。
ohfuji様はいかがでしょうか?
(もちろん「lengthBこんなダサい命名しない」が回答でも悪く思いませんのできたんないご意見を!)