このへんとかこのへんとかで流行っているのでうちでも言及しておこう。
この2つは、read-onlyである場合を除いては、利用者側からは区別できない。
区別する価値があるのは実装者側にだけだ。
「publicフィールドは駄目だ。フィールドはprivateにし、プロパティを使え」と、一律強制するのをよく見かける。
しかし、getter、setterともにpublicであれば、それはフィールドと何も変わらない。
以前どこかで、「プロパティにしておけば、後から実装方法を変更できる」というようなのを読んだ覚えがある。だからとりあえずプロパティにしておくということだ。
しかし、C#ならば、最初はフィールドにしておいて、あとからプロパティにすることも可能だ。
これは、プロパティが存在しないC++やJavaにおいて、「アクセッサにしておけば…」と書いてあったのかもしれない。
いずれにせよ、後から読み取り専用にするだとか、後から入力チェックを加えるだとかといった仕様変更は好ましいものではない。
ちなみに、Eiffelという言語は面白いアプローチをとっている。
Eiffelでもpublicフィールドというものはある。が、publicであるかどうかにかかわらず、フィールドはそのインスタンス外からはread-onlyなのだ(たぶんね。間違ってたら指摘してください)。
Eiffelにはプロパティは無い。オブジェクトのメンバ変数を書き換えるときは、(その変数がpublicであっても)Javaのようなsetter関数を使わなければいけない。
こういう言語ならば、プロパティだフィールドだということに悩むこともなくなるかもしれない。が、俺はこの非対称性が嫌いだったりする。
ここからわかるように、Eiffelではpublicフィールドを宣言すると、それはC#のread-onlyプロパティと同じようにふるまう。このことをとある本では、「データは使われるためにあるものであり、隠蔽されるためにあるものではない。C++の『データは隠蔽せよ』という教えは誤りである。Eiffelではデータは自動的に適切に公開される」とかなんとか書いてあったような気がする。private変数とpublicプロパティを比較してどうする…
なお、Eiffelではフィールドなどというものはない、と考えることも可能。
Eiffelには「関数」と「手続き」しかない。
関数とは戻り値を返し、オブジェクトの状態を変更できないメンバ。getter。C++でいうconstメンバ関数。
手続きとは戻り値を返さず、オブジェクトの状態を変更できるメンバ。setter。C++でいう、constでないメンバ関数。
そして、フィールドは関数の一種。定数も関数の一種。ただ明示的にgetアクセッサが書いてないだけ、と。
ちなみに、今の仕事で直してるプログラム(C#)はひどい。
どういうものかというと…
- ローカル変数がほとんど無い。1つの関数の中でしか使わない変数でもフィールドになっている場合がある。また、複数の関数から参照する必要は無いのに、複数の関数の中で使われている同じ役割の変数をフィールドにしている。
- そのくせ、そのフィールドを参照しない。外部からの利用を想定しないフィールドも常にpublicプロパティでラップし、クラス内からもそれを使ってアクセスしている。
もうね…orz