2012年12月28日金曜日

Getter/Setterを減らす

Getter/Setterばかりが目立つようなクラスは、きっとドメインモデル貧血症に陥っている。だから、もっと振る舞いを持たせて、カラフルな名前を付けたり。それに、Setterで内部状態を外から操作できるようでは、カプセル化しきれていない。状態が変化しないImmutableなクラスを目指して、少なくともSetterは減らしていきたい。ただ、フレームワークが要求したり、と完全に消し去ることはできないと思う。というわけで、なるべくうまく付き合いたい。

なんてことを考えるようになった。そのキッカケや経緯、参照したパターンについてまとめておく。

『オブジェクト指向エクササイズ』("Object Calisthenics") の9つのルールに、Getter/Setterを禁じるものがある。
ルール9:Getter、Setter、プロパティを使用しないこと
Rule 9: No getters/setters/properties
初めてこのルールを知ったときは、意図には同意できたけれど、適用しようとは思わなかった。同意できたのは、単にフィールドをプライベートにして値の取得/設定をすることが、オブジェクト指向の特徴の一つであるカプセル化だという説明に違和感を持っていたから。Getter/Setterを通せばAPI変更に強くなるとは言え、値を自由に設定していたら、隠蔽できているとは思えない。適用しようと思わなかった最大の理由は、今思うと、実装をイメージできなかったからだと思う。だから、適用しようにもできなかった、の方が実態に近い。

「求めるな、命じよ("Tell, don't ask")」なんて言い換えられても、やっぱりよく分からなかったけれど、最近、少しずつ分かってきた気がする。痛い目を見たり(Setterでインスタンスへの参照を返していたせいで意図しない変更を加えてしまったり、名前がgetで始まるメソッドをGetterだと思って気楽に使っていたら思わぬ副作用があって面食らったり)、それで『Java言語で学ぶリファクタリング入門』や『リーダブルコード』、"Effective Java 2nd Edition"の内容を応用しようと試行錯誤したりして、ようやく使う/使わないの判断が少しクリアになった。

例えば、Remove Setting Methodのリファクタリングを適用すると、初期化のためだけのSetterを使わずに済ませられる。代わりに、(デザインパターン"factory method"を適用していたら、factory methodを経由して)コンストラクタで初期化することになる。そのまま、"Effective Java 2nd Edition"の"Item 15: Minimize mutability"してMutableにできれば、Setterは要らなくなる。あるいは、『リーダブルコード』のいう〈カラフルな単語〉を使った名前を付けようとすれば、そんな名前が付けられるくらい十分に抽象化しようとすれば、自然とGetter/Setterのような無味乾燥な名前は相応しくなくなる。

ただ、それでGetter/Setterがなくせるかというと、そうはならないと思う。現実問題、フレームワークから利用されるためにEntity Beanにする必要があるクラスも出てくるし、抽象度の低いクラスで融通が利かなくなる。Getter/Setterを使用しないというのは、あくまでエクササイズのルールであって、実戦における規約ではない。だから、リファクタリングSelf Encapsulate Fieldや"Effective Java 2nd Edition"の"Item 14: In public classes, use accessor methods, not public fields"があるんだと思う。

References


0 件のコメント:

コメントを投稿