使用单例设计模式实施解决方案的建议

Suggestions for implementing a solution using Singleton design pattern

我需要实施一个解决方案作为测试框架的一部分,我正在考虑单例模式,原因如下所述。但是,我无法实现我预期的解决方案,因此需要一些 suggestions/inputs 可能的实现。

问题陈述: 我有一个环境(我正在测试的产品的环境)配置属性文件,我想加载它并使测试框架可以全局访问参数的值。 我想使用单例模式,因为这些属性是一次性值(如果尝试多次初始化应该报告异常),应该全局可用并且可以一次性访问这些方法。

但是,properties/parameters 的列表确实很长,因此将其分成模块 (类) 是明智的。对于下面的解释,我尝试了组合。

例如

public class Configuration {
    private static Configuration configObj;
    private static Database dbDetails;
    private static Machine macDetails;
    //...
    //... many more modules

    public static synchronized void createInstance(Properities envProps){
          //Should create only one instance of Configuration 
          // and should also initialize Database & Machine objects.
    }

    public static Configuration getConfigObject(){
         return configObj;
    }
}


public class Database {
    private static String dbConnectString;

    public Database(String dbcs){
         dbConnectString = dbcs;
    }

    public static String getDbConnectString(){
         return dbConnectString;
    }
}


public class Machine {
    private static String hostname;
    private static String loginUsername;

    public Machine(String hostname,String loginUsername){
        this.hostname = hostname; //It may include some trimming/cleaning
        this.loginUsername = loginUsername;
    }

    public static String getHostName(){
        return hostname;
    }
}

PS: 只是用于理解我的问题陈述的示例输入代码。

期望: 现在的期望是,在尝试获取主机名时,我应该通过 Configuration 静态对象进行单点访问(假设我已经初始化了所有成员变量成功)即

字符串主机名 = Configuration.getHostname();

字符串主机名 = Configuration.getConfigObject().getHostname();

当前问题: 如何使用组合或继承创建一个引用所有方法的静态对象(从概念上讲,组合是正确的方法)。

多重继承本来可以解决这个问题,但是Java不支持所以排除了。也不能考虑接口,因为重写所有方法既乏味又冗长,而且 parameters/methods 会随着时间不断变化。

欢迎所有建议,即使它需要放弃这种设计模式并尝试不同的东西。

您将无法"automatically" 将静态调用委托给模块。即使调用不是静态的,如您所说,Java 也不支持多重继承。

选项 1:

让您的主要 Configuration class 提供静态方法 return 实例到您的模块。每当你想读取配置条目时,首先获取模块实例,然后查询条目本身:

Configuration.getDatabaseConfiguration().getServerName();

这种方式的好处是很清楚你指的是你配置的哪一部分。如果您只使用 Configuration.getServerName(),则无法区分是要检索数据库的服务器名称还是网络服务器的名称。

选项 2:

如果您能够使用 Java8 并且您的配置很大,但非常简单(在编译时静态已知或可从极少数实例中提取),您可以考虑使用新的默认接口方法( https://blog.idrsolutions.com/2015/01/java-8-default-methods-explained-5-minutes/).

然后您将为每个模块创建一个接口,其中所有 getter 都有默认实现。您的主要配置 class 将在不覆盖任何方法的情况下实现所有模块接口。这样所有的配置项都可以从一个对象中查询出来,但是你还是得通过静态方法来获取这个对象。这与您所能得到的最接近多重继承。不过,我肯定会推荐选项 1。