2000年代に、私の同僚は、パブリックメソッドを仮想または抽象化するのはアンチパターンだと言っていました。
たとえば、彼は次のようなクラスはうまく設計されていないと考えました。
public abstract class PublicAbstractOrVirtual
{
public abstract void Method1(string argument);
public virtual void Method2(string argument)
{
if (argument == null) throw new ArgumentNullException(nameof(argument));
// default implementation
}
}
彼は言った
- 実装
Method1
およびオーバーライドする派生クラスの開発者はMethod2
、引数の検証を繰り返す必要があります。 - 場合には、基本クラスの開発者は、カスタマイズの一部の周りに何かを追加することを決定し
Method1
たりMethod2
、後で、彼はそれを行うことはできません。
代わりに、私の同僚がこのアプローチを提案しました:
public abstract class ProtectedAbstractOrVirtual
{
public void Method1(string argument)
{
if (argument == null) throw new ArgumentNullException(nameof(argument));
this.Method1Core(argument);
}
public void Method2(string argument)
{
if (argument == null) throw new ArgumentNullException(nameof(argument));
this.Method2Core(argument);
}
protected abstract void Method1Core(string argument);
protected virtual void Method2Core(string argument)
{
// default implementation
}
}
彼は、パブリックメソッド(またはプロパティ)を仮想または抽象化することは、フィールドをパブリックにすることと同じくらい悪いと私に言った。必要に応じて、フィールドをプロパティにラップすることにより、後でそのフィールドへのアクセスをインターセプトできます。同じことがパブリック仮想/抽象メンバーにも当てはまります。ProtectedAbstractOrVirtual
クラスに示されているようにラップすることで、基本クラス開発者は仮想/抽象メソッドへの呼び出しをインターセプトできます。
しかし、私はこれを設計ガイドラインとしては見ていません。マイクロソフトでさえそれに従いませんStream
。これを確認するためにクラスを見てください。
そのガイドラインをどう思いますか?それは理にかなっていますか、それともAPIを過度に複雑にしていると思いますか?
protected
抽象クラスのプライベートメンバーを派生クラスに公開する場合に最も便利です。いずれにせよ、私はあなたの友人の意見を特に心配していません。特定の状況に最も適したアクセス修飾子を選択してください。
virtual
、オプションでオーバーライドできます。 メソッドはオーバーライドされない可能性があるため、おそらくパブリックにする必要があります。メソッドを作成するabstract
と、それらをオーバーライドする必要があります。コンテキストprotected
では特に有用ではないため、おそらくである必要がありpublic
ます。