【问题标题】:Why is it mandatory to have private Constructor inside a Singleton class为什么在 Singleton 类中必须有私有构造函数
【发布时间】:2012-04-01 10:26:06
【问题描述】:

这是我获取数据库连接的单例类。

我在这里有一个问题:为什么在单例类中必须有一个私有构造函数(在我的整个应用程序中,我只调用这个类一次)并且可以使用静态方法来实现一个类的实例?

这个私有构造函数是可以避免的,还是强制的?

 public class ConnPoolFactory {
        private static DataSource dataSource;
        private static Connection connection;

        private ConnPoolFactory() {
            System.out.println(" ConnPoolFactory cons is called ");
        }

        public static synchronized Connection getConnection() throws SQLException {

            try {

                if (connection == null) {
                    Context initContext = new InitialContext();
                    Context envContext = (Context) initContext
                            .lookup("java:/comp/env");
                    dataSource = (DataSource) envContext.lookup("jdbc/Naresh");
                    connection = dataSource.getConnection();
                } else {
                    return connection;
                }

            } catch (NamingException e) {
                e.printStackTrace();
            }

            return connection;

        }
    }

【问题讨论】:

  • 感谢您的回答,但是为什么其他人会创建我的 Singleton 类的实例,因为它是我的应用程序并且我可以完全控制它??
  • 如果您不将数据声明为私有,其他人将不会访问您的数据:如果您是唯一从事该项目的开发人员并且可以完全控制它,那没关系。但是当其他开发人员开始您的项目时,他们不会知道不允许他们创建更多类的实例。顺便说一句,你自己也可能不小心忘记它:)
  • 顺便说一句:这不是单例,因为您必须在某处创建一个实例。你有一个实用程序类,它也必须有一个私有构造函数。

标签: java design-patterns


【解决方案1】:

否则每个人都可以创建你的类的实例,所以它不再是单例了。根据定义,单例只能存在一个实例。

【讨论】:

  • 为什么其他人会创建我的 Singleton 类的实例,因为它是我的应用程序,而我可以完全控制它??
  • 您永远不知道有一天您的应用程序会发生什么。该项目可以增长,并且您将获得更多的开发人员。所以只要你的项目真的很小,并且你可以完全控制它,你可以用任何你喜欢的方式来做,但是一旦项目变得更复杂,你需要强制执行规则:“singleton is unique” .
  • @user1254422 - 大多数人在多人的团队中工作,这就是他们说“其他人”的原因。但是,即使只有你一个人,一不小心也可能不小心创建了多个实例。私有构造函数是一种防止多个实例的安全机制,因为创建实例的唯一方法是通过静态 get 方法。
  • @user1254422:同样的,如果你对项目有完全的控制权,你就不需要将数据声明为私有,对吧?但是一旦项目变得更大,您就必须开始执行规则。
【解决方案2】:

如果没有这样的私有构造函数,Java 将为您提供一个默认的公共构造函数。然后您可以多次调用此构造函数来创建多个实例。那么它就不再是一个单例类了。

【讨论】:

    【解决方案3】:

    如果你不需要懒启动:

    public class Singleton {
        private static final Singleton instance = new Singleton();
    
        // Private constructor prevents instantiation from other classes
        private Singleton() { }
    
        public static Singleton getInstance() {
                return instance;
        }
    }
    

    是最好的方式,因为是线程安全的。

    【讨论】:

      【解决方案4】:

      单例模式通常包含一个 非公共 构造函数,原因有两个。构造函数必须存在,因为如果根本没有构造函数,则包含公共默认构造函数。但是,如果您有一个公共构造函数,人们可以随意制作他们自己的单例(有人不可避免地会这样做,这意味着可以有多个)。

      不过,它不必是私有的。事实上,正如我所听到的,GoF 指定的单例模式出于某种奇怪的原因提到了一个 protected 构造函数。我听说了一些关于继承的事情,但无论如何,单例和继承根本不能很好地结合在一起。

      甚至可以有一个公共的构造函数,只要它可以检测一个实例是否已经存在并且如果存在就抛出一个异常或其他东西。这足以保证单身。但这并不常见,因为这样做会使事情复杂化,因为它提供了两种明显的获取实例的方法——只有一种会真正起作用。如果您不希望外部代码能够创建第二个实例,为什么构造函数应该是公共接口的一部分?

      【讨论】:

        【解决方案5】:

        对于singleton pattern,您使用私有构造函数来确保不能创建其他实例,否则它不会是单例。

        【讨论】:

          【解决方案6】:

          静态类与单例的不同之处在于,单例类强制始终最多有一个实例。静态类没有实例,只是一组静态函数和静态数据。

          所以对于一个单例类,即一个最多有一个实例的类,那么就需要一个私有构造函数。

          在您的示例中,Singleton 类似乎比静态类更适合 - 因为连接和 dataSource 成员。将这些成员设为私有,将您的构造函数设为私有,并提供引用静态 ConnPoolFactory 实例的静态方法。如果instance为null,则新建一个,否则直接使用。

          【讨论】:

            【解决方案7】:

            对于单例和实用程序类,您可以使用 enum,它是最终类并隐式定义了一个私有构造函数。

            enum Singleton {
                 INSTANCE
            }
            

            enum Utility {;
            
            }
            

            在上面的示例中,您有一个实用程序类,因为您没有实例字段、方法并且不创建实例。

            【讨论】:

              【解决方案8】:

              您所说的评论是,如果我是我的应用程序的完全所有者,并且我永远不会犯下直接使用公共构造函数创建单例类实例的错误,而是会使用静态方法来获取它。但在现实世界中,应用程序经常在多个开发人员之间切换。如果新开发人员不知道您只需要应用程序中的一个类实例,他/她可能会使用公共构造函数意外创建另一个实例。

              【讨论】:

                【解决方案9】:

                这是强制性的。您的代码可能没问题,但其他人可以使用此代码并实例化另一个对象,或者您可能会不小心这样做。这条路很安全。

                【讨论】:

                  【解决方案10】:

                  单例定义:

                  确保只需要为整个主堆栈(每个主类)创建一个对象。

                  如果你想满足上面的陈述,那么我们应该给构造函数作为一个私有的。实际上,通过单例我们得到的是 ref 而不是对象,这就是为什么它不是强制性的,然后我们可以在其他类中创建对象但我们不能访问引用(构造函数作为公共)。

                  例如:

                  public class SingleTon {
                  
                      private static SingleTon s;
                      public SingleTon() {}
                  
                      public static SingleTon getInstance() {
                          if (s == null) {
                              s = new SingleTon();
                              System.out.println("ho ho");
                          } else{
                              return s;
                          }
                          return s;
                      }
                  }
                  

                  其他类:

                  public class Demo {
                  
                      public static void main(String[] args) {
                          //SingleTon s=SingleTon.getInstance();
                  
                          SingleTon s11=new SingleTon();
                          SingleTon s12=new SingleTon();
                          s11.getInstance();
                          s12.getInstance();
                      }
                  }
                  

                  输出:

                  ho ho
                  

                  【讨论】:

                  • 无法使用公共构造函数创建单例,因为它会创建新实例。这违背了单例的目的
                  猜你喜欢
                  • 2012-05-01
                  • 1970-01-01
                  • 2019-10-06
                  • 1970-01-01
                  • 2012-07-16
                  • 1970-01-01
                  • 2019-10-16
                  相关资源
                  最近更新 更多