复制/扩展静态类功能的最佳方法是什么?

时间:2009-02-17 20:21:28

标签: java class oop static

我正在处理的应用程序有一个维护数据库连接的类。此类的所有成员都是静态的,以强制执行类似单一的模式,因此实际的连接逻辑在静态初始化程序块中执行:

public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    static {
        sessionFactory = new Configuration().configure().buildSessionFactory();
    }

    static void openSession() {
        //open session with sessionFactory
    }

    public static Session currentSession() {
        //return the currently open session
    }

    static void closeSession() {
        //close the currently open session
    }

}

但是,应用程序现在需要打开与第二个数据库的数据库连接。现在这个类的结构方式,在保持上述模式的同时维持第二个连接的唯一方法是创建第二个类(类似于SecondHibernateUtil)并更改初始化块中的一行配置。这感觉真的是浪费了大量的复制/粘贴。

任何人都可以提出一种方法,我可以重新设置此设置以同时维护多个连接,同时不会对已调用现有方法的代码过度破坏吗?

9 个答案:

答案 0 :(得分:2)

首先,它可能不应该是静态的。

答案 1 :(得分:2)

保留静态方法并让它们委托给默认实例的相应实例方法。

对于辅助数据库,允许通过任何方式创建更多实例,并通过其实例方法访问它们。

然后你可以去掉静态方法的调用者,当它们全部消失时删除静态方法。

答案 2 :(得分:1)

嗯,现在是正确的事情。

无法添加第二个连接并保留您描述的模式。

相反,你可能会尝试把事情搞定。

您有两种选择。

第一个选项。保持一团糟,让它变得有点糟糕(不告诉你的客户)

  1. 创建一个处理连接的实用程序类。这个时间不限于两个。请改用地图,不要使其静止。
  2. 更改静态类使用该新实用程序对象。
  3. 创建新的连接实用程序(HibernateUtility2)并使用该新的实用程序对象。

    // Create a new utility class using a map instead.
    class HibernateUtility { 
    
        private Map<String, SessionFactory> factories;
        private HibernateUtility instance;
    
        public  static HibernateUtility getInstance() { 
            if( instance == null ) { 
            instance = new HibernateUtility();
            }
            return instance;
        }
    
        private HibernateUtility() {}
    
        private void check( String whichConnection ) { 
            if( !factories.containsKey( whichConnection ) ) {
                // start the connection
                factories.put( whichConnection, new Configu..
                //... etc etc ().configure().buildSessionFactory() );
            }
        }
    
        void openSession( String whichConnection ) {
            check( whichConnection );
            //open session with sessionFactory
            factories.get( whichConnection ).open(); //etcetc
        }
    
        Session currentSession( whichConnection ) {
            check( whichConnection );
            //return the currently open session
            factories.get( whichConnection ) .....
        }
    
        void closeSession( String whichConnection ) {
            check( whichConnection );
            //close the currently open session
            factories.get( whichConnection );
        }       
    }
    
    //------------------------------------------
    // Make your existing class call that class
    public class HibernateUtil {
    
        static void openSession() {
            //open session with sessionFactory
            HibernateUtility.getInstance( "one" ).openSession();
        }
    
        public static Session currentSession() {
            //return the currently open session
            HibernateUtility.getInstance( "one" ).currentSession();
        }
    
        static void closeSession() {
            //close the currently open session
            HibernateUtility.getInstance( "one" ).closeSession();
        }
    }
    
    //------------------------------------------            
    // Make the new connection use that class too.
    public class HibernateUtil {
    
        static void openSession() {
            //open session with sessionFactory
            HibernateUtility.getInstance( "two" ).openSession();
        }
    
        public static Session currentSession() {
            //return the currently open session
            HibernateUtility.getInstance( "two" ).currentSession();
        }
    
        static void closeSession() {
            //close the currently open session
            HibernateUtility.getInstance( "two" ).closeSession();
        }
    }
    
  4. 这样现有的客户端代码就不会中断。

    第二个选项。清理混乱并相应地修改代码。

    在第二个选项中,您创建的对象与之前描述的HibernateUtility非常相似,但这次您不添加方法 openSession ,也不添加 closeSession 。属于那个界面。

    使用这种非静态方法,您可以创建可以连接到不同配置的不同实例。

    你只需使用 currentSession ,如果会话不存在,则创建一个新的,并作为参数接收一个标识符(很像前一个示例中的“one”和“two”)

    在第二个选项中,您必须更改客户端代码以使用正确的实现。

    注意: SO中的代码格式错误,我花了一些时间来格式化它,它看起来不是很好:(

答案 3 :(得分:1)

我很久以前就看过这个问题而且由于你提出的确切问题,我决定永远不要制作这样的静态课程。实际上有2个问题...

首先它不可重用(正如你所注意到的)并且修复它是一个艰难的重构。

其次,你不能拥有第二个实例(似乎程序员认为只有一个东西,他们认为他们永远不需要改变日期的前两位数!)

如果您决定要使用工厂模式(或类似spring)的第二个实例,这是一个微不足道的更改 - 只需将变量传递给工厂以指示您想要的实例 - 但是要从静态重构上课只是个婊子。

你甚至应该小心不要滥用工厂模式。如果你真的倾向于那个方向,学习并接受春天 - 它将与你的自然倾向相结合,以改善你的代码。

答案 4 :(得分:0)

有一种不太好的方式,有时除了复制整个销售课程并与复制品一起生活外,没有其他真正的选择。

我知道这听起来确实糟糕但是自从它从hibernate文档中复制以来,这个类实际上有多少次改变了?

我确定有人会建议将整个应用程序转换为Spring SessionFactory以及所有这些东西,但除非您的应用程序是Hibernate“Hello World”,否则我猜这可能需要一点时间超过几个小时。

答案 5 :(得分:0)

学习春天。如果你已经在使用Hibernate,那么学习足够的Spring来处理这个问题并不是一件容易的事。 Spring Source的人们已经比以往更好地解决了这个问题。

Spring事务对JDBC,Hibernate,iBatis或Spring支持的任何其他持久性技术都有效。如果您已经在使用Spring,请不要重新发明他们已经做得更好的事情。使用他们的交易。

如果你有多个数据库,并且你作为一个单独的工作单元执行写入操作,那么你就足够了解两者的XA驱动程序,对吗?

答案 6 :(得分:0)

有两种可能的答案;让我们看看两者。

一种是将其转换为非静态。可以说这首先比静态接口更好,因为你在接口后面有一个具体的对象(SessionFactory)。这样做的好处是你可以推迟创建SessionFactory直到你需要它(如果你不这样做,就永远不会创建它)。创建一个静态方法来获取默认的HibernateUtil对象,如果不存在则创建它。您可能想要或不想要第二个HibernateUtil。

另一种方法是创建一个全新的静态对象HibernateUtil2,它在必要时委托给HibernateUtil。但请注意,这些不会以任何类似继承的方式相互关联,因为静态不能在接口中使用。

我会推荐第一条路线,其他条件相同,但您的具体情况可能需要第二条路线。

答案 7 :(得分:0)

解决这个问题的破坏性最小的方法是将第二个静态变量添加到类中,在静态块中初始化第二个SessionFactory,然后修改“currentSession”静态方法以使用String参数根据您的业务选择适当的实例/代码逻辑。

答案 8 :(得分:0)

我不知道这个问题的一般解决方案,但是在这里你可以声明非静态SessionFactory并在代码中设置配置,而不是在hibernate.cfg.xml文件中!所以你可以有多个SessionFactory连接到多个数据库以获得更多不同的映射。