Параметры конструктора - Правило большого пальца - PullRequest
20 голосов
/ 08 апреля 2009

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

Ответы [ 9 ]

35 голосов
/ 08 апреля 2009

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

Пример:

public class ReallyComplicatedClass {
    private int int1;
    private int int2;
    private String str1;
    private String str2;
    // ... and so on
    // Note that the constructor is private
    private ReallyComplicatedClass(Builder builder) {
        // set all those variables from the builder
    }
    public static class Builder {
        private int int1;
        private int int2;
        private String str1;
        private String str2;
        // and so on 
        public Builder(/* required parameters here */) {
            // set required parameters
        }
        public Builder int1(int newInt) {
            int1 = newInt;
            return this;
        }
        // ... setters for all optional parameters, all returning 'this'
        public ReallyComplicatedClass build() {
            return new ReallyComplicatedClass(this);
        }
    }
}

И в вашем коде клиента:

ReallyComplicatedClass c = new ReallyComplicatedClass.Builder()
        .int1(myInt1)
        .str2(myStr2)
        .build();

См. Страницы 7-9 из Effective Java Reloaded [pdf], презентация Джоша Блоха на JavaOne 2007. (Это также пункт 2 в Effective Java 2nd Edition , но я не не пригодится, поэтому я не могу процитировать его.)

12 голосов
/ 08 апреля 2009

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

8 голосов
/ 08 апреля 2009

Code Complete 2 рекомендует довольно разумный предел семи параметров для любого метода.

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

4 голосов
/ 08 апреля 2009

Не думаю, что вы можете сказать, что подходящим числом является «семь, не более» или «пять».

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

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

Пример плохого конструктора:

public NightWatchman(int currentFloor, int salary, int hapiness) {...}

Здесь NightWatchman создается с некоторыми значениями по умолчанию, которые почти наверняка изменятся за короткое время. Кажется забавным, что объекту сообщают об их значениях одним способом, а затем имеют их другим способом (через их установщики) в будущем.

Пример лучшего конструктора:

public GateWatchman(Gate watchedGate, boolean shootOnSight) {...}

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

У меня мог бы быть класс ShootingGateWatchman и PoliceCallingGateWatchman - т.е. параметр интерпретируется как часть идентификатора объекта.

2 голосов
/ 08 апреля 2009

Мне нужно знать больше о том, что делает класс и каковы его параметры, но есть вероятность, что у класса слишком много обязанностей. Можно ли разделить класс на более мелкие независимые классы?

Использование сеттеров не решает проблему класса, имеющего много зависимостей / параметров. Он просто перемещает проблему в другое место и не заставляет вводимые параметры.

Для методов я стараюсь следовать совету из книги «Чистый код», чтобы иметь не более 3 параметров на метод (IIRC). Для конструкторов у меня может быть больше параметров, потому что обычно конструктор будет вызываться моей структурой внедрения зависимостей, а не мной.

Шаблон построения, упомянутый mmyers, также является хорошим решением при построении сложных объектов, и невозможно сделать их менее сложными.

2 голосов
/ 08 апреля 2009

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

1 голос
/ 08 апреля 2009

Обычно я бы сказал, что не более пяти, из правила 7 +/- 2 кратковременной памяти и некоторого пессимизма в отношении концентрации внимания программиста. Примечание: я бы посчитал список varargs как одну сущность.

Если вы действительно вынуждены создавать объект за один раз, вы обычно можете собирать связанные параметры в объектах простых значений и передавать их в конструктор. Постарайтесь убедиться, что объекты-значения имеют некоторый концептуальный смысл, а не просто случайные наборы информации ...

0 голосов
/ 08 апреля 2009

Это зависит.

Если некоторые параметры относятся к одному типу и могут быть смешаны, я бы допустил довольно небольшое число (скажем, 5).

Если параметры бывают разных типов, поэтому они не могут быть перепутаны, я бы допустил еще немного. Десять будет близко к пределу.

0 голосов
/ 08 апреля 2009

Как насчет передачи объекта Param => Value Map в конструктор? Если вызывающая сторона пропускает какие-либо критические параметры, пусть конструктор выбросит исключение.

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

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