Дизайн - глобальные настройки из потребительского модуля

Я пытаюсь создать библиотеку. В моем коде были константы, которые были разными временными задержками и определенными строковыми значениями в коде. Я мог бы выделить их в отдельный постоянный класс, чтобы получить что-то вроде

Delays.LENGTH_SHORT (кажется чище)

Они связаны со многими разными классами внутри кода библиотеки.

Теперь проблема заключается в том, чтобы сделать его настраиваемым от вызывающего потребителя (то есть, если потребитель предоставляет значения, затем используйте их, в противном случае используйте предустановленные значения). Со стороны потребителя я решил использовать шаблон Builder для создания конфигурации и передачи ее в init модуля библиотеки (это происходит только один раз в его жизненном цикле).

Есть ли способ сохранить указанный выше синтаксис и при этом принять конфигурацию от потребителя (параметры настраиваются только один раз во время init, в остальное время он полностью ведет себя как постоянный)?

Чтение из файла оказалось дорогостоящим.

Предполагается ли, что ваша библиотека будет поддерживаться другими приложениями? В противном случае я бы рекомендовал использовать SharedPreferences для постоянного сохранения строк и продолжительности времени. Несмотря на то, что вы также можете использовать /res/values/Strings.xml, чтобы сохранить значения String по умолчанию.

procra 26.10.2018 09:57

Предполагается, что библиотека используется приложением для определенной функции. В этом потреблении приложение может настроить определенное поведение использования во время init с помощью этих настроек. Эти настройки, установленные один раз, затем используются во многих независимых классах библиотеки. SharedPreferences также будет похож на File R / W. strings.xml не допускает перезаписи в том же месте, если настройки отличаются от настроек по умолчанию (настроенных клиентом), и потребуется перепроверка во всех точках использования. Не правда ли? Я что-то упускаю?

grad9 28.10.2018 02:02
0
2
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для констант, которые могут принимать значение только из фиксированного набора значений, всегда лучше использовать перечисления 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);
    }
}

Пожалуйста, проверьте классы библиотеки и клиента на предмет использования. - Использует паттерн Строитель. - Он имеет методы init () и init (Configuration), позволяющие полностью полагаться на значения библиотеки по умолчанию. - ConfigurationBuilder поддерживает предоставление некоторых или всех значений конфигурации для переопределения. - В настоящее время можно переопределить все три параметра конфигурации - continent, poolSize и defaultLabel. Однако, если некоторая конфигурация является частной для библиотеки, просто удалите метод withXXX для этого свойства из Builder.

Надеюсь, это соответствует вашим потребностям. Хороший вопрос!

Спасибо за ваш ценный вклад. Они были полезны. Просто для пояснения, константы могут принимать "любое" значение (не фиксированное значение) от клиента приложения-потребителя. (внутри области библиотеки они работают только с одним значением, предоставленным на складе или клиентом, и время указывается в инициализации), о чем вы также упомянули в примере реализации кода. код кажется полезным. есть ли способ использовать настройки конфигурации в коде библиотеки без DI?

grad9 28.10.2018 02:33

Рад, что ответ может быть полезным. Что касается вашего последующего вопроса об использовании параметров конфигурации в коде библиотеки без DI, насколько я понимаю, после инициализации экземпляра библиотеки экземпляром конфигурации эта конфигурация может быть представлена ​​с помощью метода получения, такого как getConfiguration в классе библиотеки. Экземпляр конфигурации здесь является неизменяемым объектом, поэтому его можно безопасно раскрыть без риска того, что кто-либо его изменит. Я не получил часть DI, вы хотите избежать зависимости от совместного использования интерфейса конфигурации между клиентом и библиотекой?

punitoza 29.10.2018 03:17

Я реализовал часть доступа с помощью dagger2 (все еще хочу децентрализовать его дальше). Проблема заключалась в том, чтобы не заставить классы внутри библиотеки взаимодействовать с «Библиотекой», чтобы получить конфигурацию, которая актуальна для этих классов, а не для класса «Библиотека».

grad9 30.10.2018 08:53

Другие вопросы по теме