“公共”嵌套类与否

假设我有一个“应用程序”类。 为了初始化,它需要在构造函数中进行某些设置。 我们还假设设置的数量太多,以至于将它们放在自己的类中是很有吸引力的。

比较此方案的以下两种实现方式。

实施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 } } 

对我来说,第二种方法更为可取。 它更具可读性,因为它强调了两个类之间的关系。 当我编写代码以在任何地方实例化Application类时,第二种方法看起来更漂亮。

现在想象一下,Settings类本身又有一些类似的“相关”类,而这个类反过来也是如此。 只有三个这样的级别,类命名在’非嵌套’的情况下失控。 然而,如果你筑巢,事物仍然保持优雅。

尽管如此,我还是读过人们在StackOverflow上说嵌套类只有在外部世界不可见的情况下才是合理的。 也就是说,它们仅用于包含类的内部实现。 通常引用的异议是膨胀包含类的源文件的大小,但是部分类是该问题的完美解决方案。

我的问题是,为什么我们对嵌套类的“公开暴露”使用持谨慎态度? 还有其他反对这种用法的论据吗?

我认为没关系。 这基本上是构建器模式,并且使用嵌套类非常有效。 它还允许构建器访问外部类的私有成员,这非常有用。 例如,您可以在构建器上使用Build方法,该方法在外部类上调用私有构造函数,该构造函数接受构建器的实例:

 public class Outer { private Outer(Builder builder) { // Copy stuff } public class Builder { public Outer Build() { return new Outer(this); } } } 

这确保了构建外部类的实例的唯一方法是通过构建器。

我在Protocol Buffers的C#端口使用了非常类似的模式。

您可以使用命名空间来关联相关的事物。

例如:

 namespace Diner { public class Sandwich { public Sandwich(Filling filling) { } } public class Filling { } } 

这样做的优点就是使用类就像它们是命名空间一样,你可以选择在调用端使用use来缩写:

 using Diner; ... var sandwich = new Sandwich(new Filling()); 

如果您将Sandwich类用作Filling的命名空间,则必须使用全名Sandwich.Filling来引用Filling

那你知道怎么晚上睡觉?

您可能想查看Microsoft对该主题的评论。 基本上这是我所说的风格问题。

当我使用具有IEnumerable属性的viewmodel时,我有效使用公共嵌套类的另一个实际示例是MVC模式。 例如:

 public class OrderViewModel { public int OrderId{ get; set; } public IEnumerable Products{ get; set; } public class Product { public string ProductName{ get; set; } public decimal ProductPrice{ get; set; } } } 

我之所以使用它,是因为我不想在外面重复使用Product类,因为它只针对包含它的特定viewmodel进行了自定义。 但我无法将其设为私有,因为Products属性是公共的。

我主要使用嵌套类来微调对嵌套和/或容器类的访问。

要记住的一件事是嵌套类定义基本上是一个类成员,并且可以访问所有容器的私有变量。

您还可以使用它来控制特定类的使用。

例:

 public abstract class Outer { protected class Inner { } } 

现在,在这种情况下,用户(您的类)只能访问Inner类,如果他实现了Outer。