Могу ли я вызвать методы в конструкторе в Java? - PullRequest
43 голосов
/ 08 марта 2011

У меня есть ситуация, когда я хочу прочитать файл конфигурации только один раз, когда создается экземпляр класса.

Предположим, у меня есть метод с именем readConfig(), который читает конфигурацию и помещает ее в объект Map. Когда программе требуется использовать значение конфигурации, она считывает объект с ключом определения. Я хочу знать, что конструктор вызывает только один раз, когда это жизненный цикл. Могу ли я поместить свой метод readConfig() в конструктор, что даст мне преимущество однократного вызова или есть другой механизм для этого?

Ответы [ 7 ]

59 голосов
/ 08 марта 2011

Вы можете : для этого нужны конструкторы. Также вы даете понять, что объект никогда не создается в неизвестном состоянии (без загруженной конфигурации).

Вы не должны : вызов метода экземпляра в конструкторе опасен, поскольку объект еще не полностью инициализирован (это относится в основном к методам, которые могут быть переопределены). Также известно, что сложная обработка в конструкторе отрицательно влияет на тестируемость.

25 голосов
/ 08 марта 2011

Лучше дизайн будет

public static YourObject getMyObject(File configFile){
    //process and create an object configure it and return it
}
7 голосов
/ 31 июля 2018

Могу ли я поместить свой метод readConfig () в конструктор?

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

Если вы решите извлечь некоторую логику, созданную конструктором, в метод, как и для любого метода, вы должны выбрать модификатор доступа, который соответствует требованию метода, но в данном конкретном случае это имеет значение для защиты метода. против переопределения метода должно быть сделано рискуя сделать конструктор суперкласса несовместимым .

Таким образом, это должно быть private, если оно используется только конструктором (ами) (и методами экземпляра) класса.
В противном случае должно быть и package-private, и final, если метод повторно используется внутри пакета или в подклассах.

что даст мне пользу от одного звонка или есть другой механизм для этого?

У вас нет никаких преимуществ или недостатков, чтобы использовать этот способ.
Я не рекомендую выполнять много логики в конструкторах, но в некоторых случаях может иметь смысл инициировать несколько вещей в конструкторе.
Например, конструктор копирования может выполнять много вещей.
Несколько классов JDK иллюстрируют это.
Возьмем, к примеру, конструктор копирования HashMap, который создает новый HashMap с теми же отображениями, что и указанный параметр Map:

public HashMap(Map<? extends K, ? extends V> m) {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}

final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
    int s = m.size();
    if (s > 0) {
        if (table == null) { // pre-size
            float ft = ((float)s / loadFactor) + 1.0F;
            int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                     (int)ft : MAXIMUM_CAPACITY);
            if (t > threshold)
                threshold = tableSizeFor(t);
        }
        else if (s > threshold)
            resize();
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
            K key = e.getKey();
            V value = e.getValue();
            putVal(hash(key), key, value, false, evict);
        }
    }
}

Извлечение логики заполнения карты в putMapEntries() - хорошая вещь, поскольку она позволяет:

  • повторное использование метода в других контекстах. Например clone() и putAll() используйте это тоже
  • (незначительное, но интересное), дающее осмысленное имя, которое передает выполненную логику
2 голосов
/ 08 марта 2011

Конструктор вызывается только один раз, поэтому вы можете безопасно делать то, что хотите, однако недостатком вызова методов из конструктора, а не напрямую, является то, что вы не получаете прямой обратной связи в случае сбоя метода.Это становится сложнее, чем больше методов вы вызываете.

Одним из решений является предоставление методов, которые вы можете вызывать для запроса «здоровья» объекта после его создания.Например, метод isConfigOK() можно использовать для проверки правильности операции чтения конфигурации.

Другое решение состоит в создании исключений в конструкторе при сбое, но это действительно зависит от того, насколько «фатальными» являются эти сбои.

class A
{
    Map <String,String> config = null;
    public A()
    {
        readConfig();
    }

    protected boolean readConfig()
    {
        ...
    }

    public boolean isConfigOK()
    {
        // Check config here
        return true;
    }
};
1 голос
/ 08 марта 2011

шаблон синглтона

public class MyClass() {

    private static MyClass instance = null;
    /**
    * Get instance of my class, Singleton
    **/
    public static MyClass getInstance() {
        if(instance == null) {
            instance = new MyClass();
        }
        return instance;
    }
    /**
    * Private constructor
    */
    private MyClass() {
        //This will only be called once, by calling getInstanse() method. 
    }
}
1 голос
/ 08 марта 2011

Можно. Но помещая это в конструктор, вы затрудняете тестирование вашего объекта.

Вместо этого вы должны:

  • обеспечивает настройку с помощью установщика
  • есть отдельный init() метод

Среды внедрения зависимостей предоставляют следующие возможности.

public class ConfigurableObject {
   private Map<String, String> configuration;
   public ConfigurableObject() {

   }

   public void setConfiguration(..) {
       //...simply set the configuration
   }
}

Пример 2-го варианта (лучше всего использовать, когда объект управляется контейнером):

public class ConfigurableObject {
   private File configFile;
   private Map<String, String> configuration;
   public ConfigurableObject(File configFile) {
       this.configFile = configFile;
   }

   public void init() {
       this.configuration = parseConfig(); // implement
   }
}

Это, конечно, можно написать, просто имея конструктор

public ConfigurableObject(File configfile) {
    this.configuration = parseConfig(configFile);
}

Но тогда вы не сможете предоставить имитационные конфигурации.

Я знаю, что второй вариант звучит более многословно и подвержен ошибкам (если вы забыли инициализировать). И это не сильно повредит вам, если вы сделаете это в конструкторе. Но сделать ваш код более ориентированным на внедрение зависимостей - это, как правило, хорошая практика.

1-й вариант лучше - его можно использовать как с DI-фреймворком, так и с ручным DI.

0 голосов
/ 27 января 2016

Почему бы не использовать Static Initialization Blocks?Дополнительная информация здесь: Статические блоки инициализации

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...