“公共”嵌套类与否

时间:2008-12-03 13:37:18

标签: c# class-design nested-class

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

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

实施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上说嵌套类只有在外部世界不可见的情况下才是合理的。也就是说,它们仅用于包含类的内部实现。通常引用的异议是包含类的源文件的大小膨胀,但是部分类是解决该问题的完美解决方案。

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

6 个答案:

答案 0 :(得分:22)

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

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

    public class Builder
    {
        public Outer Build()
        {
            return new Outer(this);
        }
    }
}

这确保构建外部类实例的 only 方式是通过构建器。

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

答案 1 :(得分:5)

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

例如:

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

你知道那晚会怎么睡觉?

答案 2 :(得分:0)

您可能想查看有关该主题的Microsoft has to say内容。基本上这是我所说的风格问题。

答案 3 :(得分:0)

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

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

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

示例:

public abstract class Outer
{
  protected class Inner
  {
  }
}

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

答案 4 :(得分:0)

当我使用具有IEnumerable属性的viewmodel时,我有效使用公共嵌套类的另一个实际示例是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属性是公开的。

答案 5 :(得分:0)

我不知道这是否被认为是错误的设计,但是我在用户调用Run()方法的地方创建了一些搜索类,并传入了一个包含搜索条件的对象。然后,它返回搜索结果对象的集合。

除了将SearchCriteria和SearchResult类与Search类一起使用之外,它们没有任何实用程序。因此,我将它们嵌套在Search类下以显示它们在一起。

我必须公开嵌套类,以便Search类的客户端可以使SearchCriteria传递到Search类中,以便他们可以获取Search的结果。

public class PersonSearch
{
    public PersonSearchCriteria
    {
        string FirstName {get; set;}
        string LastName {get; set;}
    }

    public PersonSearchResult
    {
        string FirstName {get;}
        string MiddleName {get;}
        string LastName {get;}
        string Quest {get;}
        string FavoriteColor {get;}
    }

    public static List<PersonSearchResult> Run(PersonSearchCriteria criteria)
    {
        // create a query using the given criteria

        // run the query

        // return the results 
    }
}


public class PersonSearchTester
{
    public void Test()
    {
        PersonSearch.PersonSearchCriteria criteria = new PersonSearch.PersonSearchCriteria();
        criteria.FirstName = "George";
        criteria.LastName  = "Washington";

        List<PersonSearch.PersonSearchResults> results = 
            PersonSearch.Run(criteria);
    }
}