zeeさんのネタに触発されて。
静的メンバって、どうやって使うのが正道なんでしょうね?
最初に一つ言っときます。コンストラクタ(というかnew)は静的メソッドの一種と考えることができます。
正確に言うと、コンストラクタは静的メソッドとインスタンスメソッド(※)のハイブリッドみたいな特異なメソッドです。
その内部ではインスタンスメンバにアクセスできるという点ではインスタンスメソッドですが、クラスに対して「新しいインスタンスを作ってよ」と依頼するという点では静的メソッドです。
※:静的メンバの対義語は動的メンバで、インスタンスメンバの対義語はクラスメンバなんでしょうが、どっちもいまひとつ分かりにくいので、ここでは「静的メンバ」と「インスタンスメンバ」を対義語として用います。
ま、それは置いといて。
静的メンバの使い道を4つほど考えてみましたが、どれもしっくりきません。
どなたか、「これぞ静的メンバだ!」というものをご存知でしたらご教示ください。
1:インスタンスの集合が持つメンバとして
先日のオブ熱イベントでちらっと言いましたが、クラスは基本的に、インスタンスの集合です。
集合ということは一種のコレクションであると考えられます。
そこで、例えば社員クラスを社員インスタンスのコレクションであると考えると、そのコレクションの属性として総社員数が考えられます。
しかし、社員クラスを社員コレクションとするのではなく、別途、社員コレクションクラスのインスタンスを作って管理した方が柔軟なように思えます。
2:シングルトンとして
シングルトンというのは、インスタンスを1つしか持たないクラスです。
身近な例では、Console.WriteLine とか、MessageBox.Show とかがこれにあたると考えられます。
Console.WriteLine は、実は Console.Out.WriteLine と同じ意味です。Console.Out は Console クラスの静的プロパティですが、同時に TextWriter クラスのインスタンスでもあり、そして、TextWriter.WriteLine はインスタンスメソッドです。
Console.WriteLine は、よく使うので短縮形が提供されているに過ぎず、静的なのは Console.Out です。
これが静的なのは、標準出力は1プロセスにつき1つしか無いからです。
MessageBox.Show はどうでしょう。
MessageBox に似たフォームを作ることは簡単にできます。そのフォームのインスタンスを作って ShowDialog すれば、MessageBox.Show と同じ効果が得られます。
フォームのインスタンスは一度にいくつでも作れます。しかし、ShowDialog できるのは、1つのスレッドにつき同時に1つだけですから、いくつも作るメリットはほとんどありません。
MessageBox は、インスタンスを作られては困るわけではないけれど、たくさん作っても仕方がないのでシングルトンなんだと思います。
シングルトンは、インスタンスが無いわけではなく、唯一のインスタンスに対するアクセス手段が静的なだけであり、本質的にはインスタンスメンバを使っていると言ってよいでしょう。
これも静的メンバの本質に迫るものではありません。
3:クラスが名前空間の場合
名前空間という言葉には、狭義の名前空間と広義の名前空間があります。
狭義の名前空間は、言語機能の namespace によって実現されるものです。
広義の名前空間とは、ある名前が一意になる範囲のことで、これは概ね、スコープのことです。
クラスが違えば、複数のクラスに同じ名前のメンバがあってもいいですよね。
メソッドが違えばローカル変数名が同じでもバッティングしませんし、あるメソッド中でのローカルスコープも名前空間になります。
このように、クラスは名前空間の機能を兼ね備えています。
俺が好んで使う例として、Directory.CreateDirectory があります。あるいは、Math.Sin もそうです。
これらにおける Directory クラスとか Math クラスは、オブジェクトの集合でもないし雛型でもありません。
これらは名前空間としての役割しか持っていません。
実のところ、こいつらは、言語仕様がどのクラスにも属さないメソッドを許すのなら、そこにあっても何も困らない連中です。
クラスのメンバでないメソッドを許さない言語の制限をなんとかかいくぐった、苦肉の策と言えるでしょう。
余談ですが、「メソッド呼び出しはオブジェクトに対するメッセージを投げることであり、仕事の依頼である」という観点に立つと、これらの異常性が際立ちます。
新しいディレクトリを作ってくれという依頼は、よくわからない Directory クラスではなく、ファイルシステムに投げるべき注文でしょう。
Math クラスに至っては何が何やら。
なお、C# 2.0 の静的クラスや、C# 3.0 から導入される拡張メソッドもこの部類です。
4:メンバが定数の場合
C# の const は、同時に静的でもあります。
C# では、値型か string しか、const にすることができません。
ですから、実質的に定数であるが、値型でも string でもない場合、仕方がないので readonly static として、定数として扱います。
これは2と3を足したような理由で、一番しょーもないものだと思います。
オブジェクト指向の中核要素であるクラスと、そのメンバという機能という観点から見て、静的メンバの有効な用法、その神髄とは一体何なのでしょうか?