「パブリック」ネストクラスかどうか
-
22-07-2019 - |
質問
クラス「アプリケーション」があるとします。初期化するには、コンストラクターで特定の設定が必要です。また、設定の数が非常に多いため、独自のクラスに配置する必要があると仮定します。
このシナリオの次の2つの実装を比較します。
実装1:
class Application
{
Application(ApplicationSettings settings)
{
//Do initialisation here
}
}
class ApplicationSettings
{
//Settings related methods and properties here
}
実装2:
class Application
{
Application(Application.Settings settings)
{
//Do initialisation here
}
class Settings
{
//Settings related methods and properties here
}
}
私にとって、2番目のアプローチは非常に望ましい方法です。 2つのクラス間の関係を強調しているため、読みやすくなっています。アプリケーションクラスをインスタンス化するコードをどこにでも書くと、2番目のアプローチはきれいに見えます。
今度は、Settingsクラス自体に同様の「関連」があることを想像してください。クラスとそのクラスも同様にそうしました。このようなレベルを3つだけ実行すると、「非ネスト」の場合、クラスの命名は手に負えなくなります。ただし、ネストした場合でも、物事は依然としてエレガントに保たれます。
上記にもかかわらず、私はStackOverflowで、ネストされたクラスは外の世界から見えない場合にのみ正当化されると言っている人々を読みました。つまり、包含クラスの内部実装にのみ使用される場合です。一般的に引用される異論は、含まれるクラスのソースファイルのサイズを大きくすることですが、部分的なクラスはその問題に対する完璧なソリューションです。
私の質問は、「一般に公開されている」ことになぜ警戒するのかということです。ネストされたクラスの使用?そのような使用に対する他の議論はありますか?
解決
大丈夫だと思います。これは基本的にビルダーパターンであり、ネストされたクラスの使用は非常にうまく機能します。また、ビルダーは外部クラスのプライベートメンバーにアクセスできるため、非常に便利です。たとえば、ビルダーのインスタンスを取得する外部クラスのプライベートコンストラクターを呼び出すビルダーのBuildメソッドを使用できます。
public class Outer
{
private Outer(Builder builder)
{
// Copy stuff
}
public class Builder
{
public Outer Build()
{
return new Outer(this);
}
}
}
これにより、外部クラスのインスタンスを構築する only 方法は、ビルダーを介して行われます。
プロトコルバッファのC#ポートでこのようなパターンを使用しています。
他のヒント
名前空間を使用して、関連するものを関連付けることができます。
例:
namespace Diner
{
public class Sandwich
{
public Sandwich(Filling filling) { }
}
public class Filling { }
}
クラスを名前空間であるかのように使用することの利点は、オプションで呼び出し側で using
を使用して物事を短縮できることです:
using Diner;
...
var sandwich = new Sandwich(new Filling());
Sandwich
クラスを Filling
のネームスペースであるかのように使用する場合、フルネーム Sandwich.Filling
を使用して Filling
を参照してください。
そしてそれを知っている夜、どのように眠りますか?
Microsoftがしなければならないことを確認することをお勧めします。トピックについてと言います。基本的に私が言うスタイルの問題です。
パブリックなネストされたクラスを有効に使用するためのもう1つの実用的な例は、IEnumerableプロパティを持つビューモデルを使用するときのMVCパターンです。例:
public class OrderViewModel
{
public int OrderId{ get; set; }
public IEnumerable<Product> Products{ get; set; }
public class Product {
public string ProductName{ get; set; }
public decimal ProductPrice{ get; set; }
}
}
Product
クラスを外部で再利用したくないのは、それを含む特定のビューモデルのみにカスタマイズされているためです。しかし、Productsプロパティはパブリックなので、プライベートにすることはできません。
私は主に、ネストされたクラスやコンテナクラスへのアクセスを微調整するためにネストされたクラスを使用します。
覚えておくべきことの1つは、ネストされたクラス定義は基本的にクラスメンバーであり、コンテナのすべてのプライベート変数にアクセスできることです。
これを使用して、特定のクラスの使用を制御することもできます。
例:
public abstract class Outer
{
protected class Inner
{
}
}
この場合、(クラスの)ユーザーは、Outerを実装している場合にのみ、Innerクラスにアクセスできます。