【问题标题】:How to make a single class responsible for construction of another class如何让一个类负责构建另一个类
【发布时间】:2020-06-25 13:42:26
【问题描述】:

我正在编写一个类库,其中包含一个名为 Application 的类。 Application 类包含 Document 对象的集合。我希望 Application 类在适当的时候单独负责“创建”(构造)Document 对象。我不希望我自己或我们的其他开发人员能够任意构造新的Document 对象。

我试图想出一些可靠的方法来强制执行此操作,但我只想出了几种可能性,它们都有缺点。

第一种方法是将Application 类嵌套在Document 类中,并使Document 构造函数私有,这样只有Application 类可以访问它。但这在结构上毫无意义,实际上与真正的关系相反。更不用说通常不鼓励公共嵌套类。

我尝试的另一种方法是将Document 构造函数设为私有,但给它一个公共的“工厂方法”,它会进行一些检查以确保它确实被Application 调用。但是当我尝试实现它时,这变得非常复杂。

我是否过于复杂了?当然,构建代码库以使开发人员可以做他们不应该做的事情是很常见的事情吗?我是否应该期望我们的开发人员(和我自己)在应该Application 获取它们时使用谨慎和常识而不是四处构建新的Document 对象? p>

或者我在尝试执行此操作时是否正确?我是否正确地追求课程只能按预期使用?毕竟,这首先是访问级别的用途——强制仅在正确的上下文中使用实体。如果这是一个合理的追求,是否有人对在这种情况下如何做到这一点有任何建议?


注意:我发现了这个类似的线程:java - make class only instantiable from specific class。但是建议的解决方案是嵌套类,由于我上面给出的原因,这不是一个好的选择。

【问题讨论】:

  • 你可以创建一个公共的新接口IDocument,然后在Application内部使用private内部Document类实现它?
  • 如果他们在同一个项目中,你可以让你的构造函数internal
  • 您可以将这些类移动到它们自己的项目中并使用internal。这可以通过反射和AssemblyInfo 设置来回避,但如果有人以您不想要的方式构建它们,那就很清楚了。
  • Application 类无论如何都不应该调用构造函数——它应该被传递一个抽象工厂方法,它用来这样做,尽管这对你的问题没有帮助。但是,我认为您正试图对其进行过度设计。
  • @DRoam 该模式称为Dependency Injection。我可以推荐this book,这是我工作的地方必读。 author's blog 也有一些有趣的东西。

标签: c# .net vb.net


【解决方案1】:

有一种方法可以做到这一点,但它有点令人费解,我不会这样做......

您可以将Document 实现放在一个单独的程序集中,并将其构造函数设为internal

然后将Application 类放在另一个程序集中(单独),并在 Document 程序集中使用InternalsVisibleTo 使Document 构造函数对Application 程序集可见。

这样只有Application 程序集或Document 程序集中的代码才能构造Document。 (当然,这可以通过将类添加到创建Document 实例的Application 程序集或Document 程序集...)

虽然我实际上并不希望Application 类直接创建Document 的实例。我想在 IDocument 类后面抽象 Document 并将工厂方法传递给 Application 以用于创建 IDocument 项目。

【讨论】:

    【解决方案2】:

    没有办法完全按照您的意愿行事。您可以做的是声明类internal/Friend 的所有构造函数,然后只有同一程序集中的类才能调用它们。然后由您决定在该程序集中声明的类型实际上会调用这些构造函数。如果你只想一堂课做,就只在那一堂课上做。这正是DataRow 类的工作原理。请注意,您不能直接创建DataRow 对象,但可以使用DataTable.NewRowDataRowCollection.Add 方法间接创建?

    【讨论】:

      【解决方案3】:

      据我所知,C# 没有提供一种方法来限制类(在本例中为构造函数)只能从特定的其他类调用。将Document 嵌套在Application 中并通过接口将其公开给其他类可能是您最好的选择——例如,请参阅this question

      【讨论】:

        【解决方案4】:

        另一个选择是使用

        [CallerFilePath] string callerFilePath = ""
        

        作为方法(或构造函数)中的参数来验证调用者是否来自您的应用程序。但是,这个仍然是运行时错误而不是编译错误。

        如果你想在编译时强制执行,你需要将这两个类移动到一个项目中,并使用 Document 的内部构造函数和 Application 中的公共方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-02-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-24
          相关资源
          最近更新 更多