设计-使用者模块的全局设置

时间:2018-10-26 05:47:04

标签: java android module configuration

我正在尝试制作图书馆。我的代码中有一些常量,它们是某种不同的时间延迟和整个代码中的某些String值。我可以将它们提取到一个单独的常量类中,以得到

Delays.LENGTH_SHORT(似乎更干净)

它们链接到库代码中的许多不同类。

现在,手头的问题是要从调用方使用者对其进行配置(即,如果使用者提供了值,则使用这些值,否则使用预设值)。从使用者的角度来看,我决定使用Builder模式来创建配置并将其传递到库模块的init中(这仅在其生命周期中发生一次)。

是否有一种方法可以保留上述语法,但仍可以接受使用者的配置(设置仅在init期间配置一次,对于所有其他时间,它的行为完全相同)?

从文件读取似乎很昂贵。

1 个答案:

答案 0 :(得分:0)

对于只能从一组固定值中获取值的常量,则始终最好使用Java枚举而不是整数或字符串或其他原始数据类型。在一段时间内,他们更好地理解和维护。理想情况下,应从属性文件中读取默认值以对其进行初始化。但是,正如您在案例中提到的那样,出于性能原因,您希望避免从文件中读取数据。设计问题始终是开放性的,可以有多种方法。我推荐的一种方法如下:

public interface Configuration {
    public Continent getContinent(); //For fixed set of values use enum
    public Integer getPoolSize(); //If the config can take any value then use the corresponding data type directly
    public String getDefaultLabel();
}

public enum Continent {
    ANTARTICA, AFRICA, ASIA, AUSTRALIA, EUROPE, NORTH_AMERICA, SOUTH_AMERICA;
}

public class ConfigurationBuilder {

    private DefaultConfiguration configurationInstance;

    private class DefaultConfiguration implements Configuration {

        //Ideally the below values should be read from a property file, instead of hard coding it here.
        private Integer poolSize = Integer.valueOf(50);
        private String defaultLabel = "DEFAULT";
        private Continent continent = Continent.ASIA;

        @Override
        public Continent getContinent() {
            return continent;
        }

        @Override
        public Integer getPoolSize() {
            return poolSize;
        }

        @Override
        public String getDefaultLabel() {
            return defaultLabel;
        }
    }

    public ConfigurationBuilder withContinent(Continent continent) {
        this.configurationInstance.continent = continent;
        return this;
    }

    public ConfigurationBuilder withPoolSize(Integer poolSize) {
        this.configurationInstance.poolSize = poolSize;
        return this;
    }

    public ConfigurationBuilder withDefaultLabel(String defaultLabel) {
        this.configurationInstance.defaultLabel = defaultLabel;
        return this;
    }

    public Configuration build() {
        return this.configurationInstance;
    }

    public ConfigurationBuilder() {
        this.configurationInstance = new DefaultConfiguration();
    }

    public static Configuration buildDefaultConfiguration() {
        return new ConfigurationBuilder().build();
    }
}

public class Library {
    private Configuration configuration;
    public void init(Configuration configuration) {
        this.configuration = configuration;
    }
    public void init() {
        this.configuration = ConfigurationBuilder.buildDefaultConfiguration();
    }
    private Library(Configuration config) {
        this.init(config);
    }
    private Library() {
        this.init();
    }

    /**
     * Library is not singleton here.
     * 
     */
    public static Library getInstance(Configuration configuration) {
        return new Library(configuration);
    }
    public static Library getInstance() {
        return new Library();
    }
}

public class Client {
    public static void main(String args[]) {
        Configuration config = new ConfigurationBuilder()
                .withContinent(Continent.AFRICA)
                .withPoolSize(20)
                .withDefaultLabel("Label")
                .build();
        Library lib = Library.getInstance();
        lib.init(config);
    }
}

请检查Library和Client类的用法。 -它使用了Builder模式。 -它具有init()和init(Configuration)方法,以允许完全依赖库的默认设置。 -ConfigurationBuilder支持提供部分或全部配置值以覆盖 -当前所有三个配置选项都是可重写的-大陆,poolSize和defaultLabel。但是,如果某些配置是Library专用的,则只需从Builder中删除该属性的withXXX方法。

希望这符合您的需求。好问题!