Есть ли какой-либо недостаток записи длинного конструктора?

Это влияет на время в загрузке приложения? или какие-либо другие проблемы при этом?

9
задан Aragorn 3 June 2010 в 07:31
поделиться

7 ответов

В вопросе неясно, что значит "длинный". Вот несколько возможных интерпретаций:

Интерпретация #1: Конструктор имеет много параметров

Конструкторы с большим количеством параметров могут привести к плохой читаемости, и существуют лучшие альтернативы.

Вот цитата из Effective Java 2nd Edition, Item 2: Consider a builder pattern when faced with many constructor parameters:

Традиционно программисты используют telescoping constructor pattern, в котором вы предоставляете конструктор только с обязательными параметрами, другой с одним необязательным параметром, третий с двумя необязательными параметрами, и так далее....

Шаблон телескопического конструктора по сути выглядит примерно так:

public class Telescope {
    final String name;
    final int levels;
    final boolean isAdjustable;

    public Telescope(String name) {
        this(name, 5);
    }
    public Telescope(String name, int levels) {
        this(name, levels, false);
    }
    public Telescope(String name, int levels, boolean isAdjustable) {       
        this.name = name;
        this.levels = levels;
        this.isAdjustable = isAdjustable;
    }
}

И теперь вы можете сделать любое из следующего:

new Telescope("X/1999");
new Telescope("X/1999", 13);
new Telescope("X/1999", 13, true);

Вы не можете, однако, в настоящее время установить только name и isAdjustable, оставив levels по умолчанию. Вы можете предоставить больше перегрузок конструктора, но очевидно, что их число будет расти по мере увеличения количества параметров, и вы даже можете иметь несколько boolean и int аргументов, что действительно внесет беспорядок в работу.

Как видите, это не очень приятный паттерн для написания, и еще менее приятный для использования (Что здесь означает "true"? Что такое 13?).

Блох рекомендует использовать паттерн builder, который позволит вам написать что-то вроде этого:

Telescope telly = new Telescope.Builder("X/1999").setAdjustable(true).build();

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

См. также

Похожие вопросы


Интерпретация #2: Конструктор выполняет много работы, которая стоит времени

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

Вот некоторые цитаты из Effective Java 2nd Edition, Item 17: Design and document for inheritance, or else prohibit it:

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

Вот пример для иллюстрации:

public class ConstructorCallsOverride {
    public static void main(String[] args) {
        abstract class Base {
            Base() { overrideMe(); }
            abstract void overrideMe(); 
        }
        class Child extends Base {
            final int x;
            Child(int x) { this.x = x; }
            @Override void overrideMe() {
                System.out.println(x);
            }
        }
        new Child(42); // prints "0"
    }
}

Здесь, когда конструктор Base вызывает overrideMe, Child еще не закончил инициализацию final int x, и метод получает неверное значение. Это почти наверняка приведет к багам и ошибкам.


Интерпретация #3: Конструктор выполняет много работы, которую можно отложить

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

Однако обратите внимание на Effective Java 2nd Edition, Item 71: Use lazy initialization judiciously. Ленивая инициализация может привести к тонким ошибкам и не всегда дает улучшение производительности, которое оправдывает дополнительную сложность. Не оптимизируйте преждевременно.

24
ответ дан 4 December 2019 в 08:14
поделиться

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

0
ответ дан 4 December 2019 в 08:14
поделиться

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

если мы передадим ссылку, она не создаст новый объект для хранения Значение. и никакой рекурсии не будет

0
ответ дан 4 December 2019 в 08:14
поделиться

Конструктор - еще одна функция. Вам нужны очень длинные функции, вызываемые много раз, чтобы программа работала медленно. Поэтому, если он вызывается только один раз, обычно не имеет значения, сколько кода внутри.

0
ответ дан 4 December 2019 в 08:14
поделиться

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

0
ответ дан 4 December 2019 в 08:14
поделиться

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

1
ответ дан 4 December 2019 в 08:14
поделиться

Самый большой недостаток, вероятно, тот же, что и при написании любой другой длинной функции - она ​​может быть сложной и трудной для понимания.

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

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

1
ответ дан 4 December 2019 в 08:14
поделиться