「パラメーターのプロパティ渡し」でプログラムを読みやすくする、というアイデアはどうだろう
2007.05.30
先日の金魚シミュレーターのソースを整理していて思ったのだが、コンストラクターにごちゃごちゃとパラメーターをたくさん渡すとものすごくプログラムが読みににくくなる。そこでフと思いついたことがあるので書いてみる。
例えばFishというクラスがあったとしよう(ちなみに、これはActionScript3.0)。
class Fish extends MovieClip {
public function Fish(speed:int, direction:int, x:int, y:int, minDistance:int, maxInfluence:int) {
this.x = x;
this.y = y;
....
}
}
コンストラクター側はこれでも問題はないのだが、呼び出す方がこんな感じになってしまう。
var f:Fish = new Fish(2, 180, 20, 20, 16, 40);
C++とかJavaで良く見るプログラミングスタイルだが、こうやってひたすら数字だけが並んでいるとやたらと読みにくい。三日後に見たらどのパラメーターが何なのかが思い出せなくて、コンストラクターのソースコードを参照せねばならない。
そこで、ActionScriptにもJavaScriptのように自由にプロパティを追加できるObjectというクラスがあることを利用して、これらのパラメーターを一つのオブジェクトのプロパティとして渡すように変更してみた。
class Fish extends MovieClip {
public function Fish(param:Object) {
this.x = param.x;
this.y = param.y;
....
}
}
すると呼び出し側はこうなる。
var f:Fish = new Fish({speed:2, direction:180, x:20, y:20, minDistance:16, maxInfluence:40});
ずっと読みやすくなったように私には思える(ちなみに、これはActionScript版のJSONである)。
もちろん、実行効率は悪くなるし、プロパティのスペルを書き間違えた時にコンパイラーが警告してくれない、などの欠点もあるが、それほど実行効率が重要ではなくて(=富豪プログラミング)、呼び出し側のプログラムの読みやすさの方が重要な場合には、こんなプログラミング・スタイルも悪くないと思ったしだいである。
ここでは読みやすさと言う観点で書かれているので、ちょっと違う話になるかも知れませんが、dependency injectionを謳うフレームワークなんかは、ご提案なさっているJSONの部分に論理名を付けてファイルとして外部化し、そのFactoryを提供していたりします。
富豪プログラムとしては面白いですよ。DI。
Posted by: やむ | 2007.05.30 at 18:36
VBの名前付き引数を思い出しました。
こっちは、タイプライブラリを参照していれば、エラーになると思います。
studentInfo(age:=19, birth:=#9/21/1981#, name:="Mary")
Posted by: 社本@ワック | 2007.05.30 at 20:18
>三日後に見たらどのパラメーターが何なのかが思い出せなくて、コンストラクターのソースコードを参照せねばならない。
コンストラクタを呼び出す側にコメントを書いておけば解決ではありませんか?
Posted by: none | 2007.05.30 at 20:50
パラメータを別の小さいクラスで定義するのはどうでしょう。パラメータの追加・削除・変更時に変更箇所が増えるデメリットがありますが、静的チェックが可能になりますし。
class Param {
int speed;
int direction;
...
}
class Fish extends MovieClip {
public function Fish(param:Param) {
this.speed = param.speed;
...
}
Posted by: katzchang | 2007.05.30 at 22:47
どうせならFishクラスのコンストラクタはこれでしょうか。
class Fish extends MovieClip{
public function Fish(param:Object){
for(var key:String in param){
this[key] = param[key];
}
}
}
これなら、Fishクラスのプロパティが増えても this.speed=param.speedという記述の追加はいらないですし、
Fishクラスがダイナミッククラスでない場合、param中のプロパティのスペルミスがあったら、実行時エラーを発生させられます。
Posted by: c9katayama | 2007.05.31 at 05:54
名前つきパラメータ、このコードまさにObjective-Cですね。
Posted by: かわうそ | 2007.05.31 at 07:50
C#はいいとこ行ってません?
var p = new System.Drawing.Point { X = 640, Y = 480 };
この場合、かなりペナルティが低いところで頑張っているように思います
Posted by: idk | 2007.05.31 at 09:45
今はIDEが賢いので、パラメータの意味はツールチップとかでIDEに教えてもらえばいいことだと思います。
名前付きパラメータのコーディングを人が行うのは面倒だと思います。
Posted by: tak | 2007.05.31 at 19:15
お望みのことは(上にコメントもありましたが) Objective-C でほぼそのまま達成されると思います。一度仕様をご覧くださいまし。
http://ja.wikipedia.org/wiki/Objective-C#.E3.83.A1.E3.82.BD.E3.83.83.E3.83.89.E5.91.BC.E3.81.B3.E3.81.A0.E3.81.97
なおこの引数を順番(アドレスオフセットにほぼ等しい)ではなく名前参照で与えるのは Smalltalk からの引用なので、本当はそちらを見るのが正解かもしれません。(が、C/Java 的見かけの言語に焼かれている、という点でやはり Objective-C が良い参考になると思います。)
僕は名前付きで引数を渡すのは悪くないと思っていますが、今以上に広まる気配はないですねえ。。
Posted by: Yasu. | 2007.06.01 at 07:19
自分もよくそんな渡し方をします。速度と管理性はトレードオフだと思うので、状況によって変えていいと思います。
Posted by: SQ | 2007.06.02 at 02:53
あれ?smalltalkは順番を入れ替えたメッセージパタンをいちいち用意することで(in:out:とout:in:の2つのメソッドを用意するなど)見かけ上実現しているだけじゃありませんでしたっけ?順不同のキーワード付き引数の機能が提案されたのはCommon Lispだったような。
Posted by: SP | 2007.06.04 at 15:22