"公共"嵌套类与否

Fre*_*ool 17 c# class-design nested-class

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

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

实施1:

class Application 
{
   Application(ApplicationSettings settings) 
   {
       //Do initialisation here
   }
}

class ApplicationSettings 
{
   //Settings related methods and properties here
}
Run Code Online (Sandbox Code Playgroud)

实施2:

class Application 
{
   Application(Application.Settings settings) 
   {
       //Do initialisation here
   }

   class Settings 
   {
      //Settings related methods and properties here
   }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Jon*_*eet 22

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

public class Outer
{
    private Outer(Builder builder)
    {
        // Copy stuff
    }

    public class Builder
    {
        public Outer Build()
        {
            return new Outer(this);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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


Dan*_*ker 5

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

例如:

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

    public class Filling { }
}
Run Code Online (Sandbox Code Playgroud)

与使用类名称空间一样使用类的优点是,您可以选择using在调用端使用缩写:

using Diner;

...

var sandwich = new Sandwich(new Filling());
Run Code Online (Sandbox Code Playgroud)

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

那你知道那晚怎么睡觉?

  • 我同意对名称空间的偏好,但有时它们并不完全有用.例如,在所讨论的示例中,语义上的"应用程序"包含"设置",但是将它们放在一个共同的命名空间中并不会传达这种含义. (2认同)