为啥我们需要私有构造函数?

Posted

技术标签:

【中文标题】为啥我们需要私有构造函数?【英文标题】:Why do we need a private constructor?为什么我们需要私有构造函数? 【发布时间】:2011-02-04 20:42:51 【问题描述】:

如果一个类有一个私有构造函数,那么它就不能被实例化。 因此,如果我不希望我的类被实例化并仍然使用它,那么我可以将其设为静态。

私有构造函数有什么用?

还有,在singleton类中使用,但除此之外,还有其他用途吗?

(注意:我排除上面的单例情况的原因是,我不明白为什么在有可用的静态类时我们根本需要单例。由于我对问题的困惑,您可能不会回答这个问题。)

【问题讨论】:

【参考方案1】:

工厂

在使用工厂模式(换句话说,用于获取类的实例而不是显式实例化的静态函数)时,私有构造函数很有用。

public class MyClass
 
    private static Dictionary<object, MyClass> cache = 
        new Dictionary<object, MyClass>();

    private MyClass()  

    public static MyClass GetInstance(object data)
    
        MyClass output;

        if(!cache.TryGetValue(data, out output)) 
            cache.Add(data, output = new MyClass());

        return output;           
    

用嵌套子代伪密封

任何从外部类继承的嵌套类都可以访问私有构造函数。

例如,您可以使用它来创建一个抽象类,可以从该类继承,但不能继承其他任何人(internal 构造函数也可以在这里工作以将继承限制为单个程序集,但private 构造函数强制所有实现为嵌套类。)

public abstract class BaseClass

    private BaseClass()  

    public class SubClass1 : BaseClass
    
        public SubClass1() : base()  
    

    public class SubClass2 : BaseClass
    
        public SubClass2() : base()  
    

基础构造函数

它们还可以用于创建从不同的、更易于访问的构造函数调用的“基本”构造函数。

public class MyClass

    private MyClass(object data1, string data2)  

    public MyClass(object data1) : this(data1, null)  

    public MyClass(string data2) : this(null, data2)  

    public MyClass() : this(null, null)  

【讨论】:

我喜欢缓存添加语句中的赋值,我已经将该语法用于延迟加载的属性和空合并运算符,在此之前我没有想到它可以同样用于常规方法现在之前。 第一个例子好像是SingletonFactory的例子? 最后一个案例的模式不必是private,但private 很好,因为没有人可以从外部使用该构造函数。我已经使用它为每个解析为相同中心代码的构造函数做出稍微不同的行为。 (例如:public MyClass(string data2) : this(null, "Hello " + data2) )此外,对于 C#6 的 get; 属性,赋值代码仅在任何构造函数区域中有效,因此它们往往在 private 构造函数中。【参考方案2】:

正如 Stefan、Adam 和其他人所指出的,私有构造函数在不希望由类之外的代码创建类的情况下很有用。单例、工厂、静态方法对象是能够限制类型构造对于强制执行特定模式有用的示例。

回答您的问题的第二部分,即如果存在静态类,为什么需要单例:单例和静态类等效。

例如,单例类可以实现接口,而静态类则不能。单例对象可以作为参数传递给方法——如果不使用包装对象或反射,这对于静态类来说并不容易。在某些情况下,您可能希望创建一个继承层次结构,其中一个(或多个)叶类是单例的 - 这对于静态类也是不可能的。再举一个例子,您可能有几个不同的单例,您可能希望在运行时根据环境或配置参数实例化其中的一个 - 这对于静态类也是不可能的。

了解语言特征并为工作选择合适的语言非常重要——它们的存在是有原因的。

【讨论】:

关于单例与静态类的优秀解释!我从中学习! FWIW,您实际上可以使用“静态初始化”来初始化非静态单例类。请参阅official documentation on this one。这是另一个让你一开始就感到困惑并最终学到一些好的东西的概念。 :-)【参考方案3】:

有时您不应该实例化一个类。这使得这一点明确并在编译器级别强制执行。

单例只是一个用例。常量类、静态方法类和其他类型的模式规定类不应是可实例化的。

【讨论】:

只是为了完整性:可以将类标记为静态,这样可以确保只允许静态成员并且不能实例化该类。【参考方案4】:

在类中创建私有构造函数的目的

    限制一个类被继承。

    限制类实例化或创建多个实例/对象。

    实现单例设计模式。

    public class TestPrivateConstructor
    
        private TestPrivateConstructor()
          
    
        public static int sum(int a , int b)
        
            return a + b;
        
    
    
    class Program
    
        static void Main(string[] args)
        
            // calling the private constructor using class name directly 
            int result = TestPrivateConstructor.sum(10, 15);
            // TestPrivateConstructor objClass = new TestPrivateConstructor(); // Will throw the error. We cann't create object of this class
        
    
    

【讨论】:

谢谢。没有人指出它会限制一个类被继承。【参考方案5】:

您可以使用它来强制singleton 实例或创建factory 类。

静态方法可以调用私有构造函数来创建该类的新实例。

例如一个单例实例:

public class Foo


  private Foo ()

  private Foo FooInstance get;set;

  public static Foo GetFooInstance ()
  
    if(FooInstance == null)
      FooInstance = new Foo();
    

    return FooInstance;
  


这只允许创建一个类的实例。

【讨论】:

【参考方案6】:

好吧,如果您的唯一目标是不希望它被实例化,那么将其设为静态就足够了。

如果,otoh,您只是不希望它在类之外被实例化,(也许您只希望用户通过在类上使用静态工厂来获得一个)-那么您需要一个私有 ctor 来允许那些可公开访问的静态工厂来实例化它。

从历史上看,将类设为静态并不总是存在... 将 ctor 设为私有是一种在将 static 关键字应用于类之前使其不可实例化(这是一个词吗?)的方法。 ..

【讨论】:

【参考方案7】:

关于单例——单例是当环境和需求满足相似的模式使用动机时使用的设计模式;静态类是一种语言特性。

正如LBushkin's answer 所讨论的,虽然使用静态类可以实现使用单例的某些目标,但单例的特定实现可能会超出静态类的单独功能集。

【讨论】:

【参考方案8】:

如果类只有私有构造函数,则不能从外部实例化。

您还可以拥有具有不同签名的私有构造函数和公共构造函数。

【讨论】:

【参考方案9】:

如果你想为一个类创建一个工厂,你可以使用一个私有的构造函数,并在类本身中添加一些静态的“工厂”方法来创建这个类。

这方面的一个例子是 Graphics 类,带有 From* 方法。

【讨论】:

【参考方案10】:

私有构造函数是一种特殊的实例构造函数。并且在某些情况下使用我们创建一个只有静态成员的类,因此创建这个类的实例是没有用的,这就是私有构造函数发挥作用的地方。

如果一个类有一个或多个私有构造函数而没有公共构造函数,则其他类(嵌套类除外)无法创建该类的实例。

示例:

class LogClass 

  public static double e = Math.E;  //2.71828

  // Private Constructor:
  private LogClass()  

   

空构造函数的声明阻止了无参数构造函数的自动生成。

如果你没有在构造函数中使用访问修饰符,默认情况下它仍然是私有的。 阅读更多:https://qawithexperts.com/tutorial/c-sharp/32/private-constructor-in-c-sharp

【讨论】:

以上是关于为啥我们需要私有构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥枚举可以有包私有构造函数?

为啥我可以在复制构造函数中访问私有变量?

为啥 GCC 在匹配函数时会查看私有构造函数?

我们啥时候需要 C++ 中的私有构造函数?

为啥私有构造函数在案例类中仍然可见?

为啥这里的 String 构造函数应该被保护而不是私有?