Если я правильно понимаю вашу проблему, вы сначала фиксируете заказ клиента в приложении «Касса» и сохраняете его в базе данных 1 (TempPosOrderPayment
), затем платеж подтверждается, и вы копируете этот заказ в приложении «Платеж» в другое база данных (PosOrderPayment
).
Предполагая, что вы используете две отдельные базы данных, приведенный выше сценарий выглядит разумным, хотя и подвержен ошибкам - что если вы забудете удалить запись из TempPosOrderPayment
после ее копирования в PosOrderPayment
?
Если бы вы могли работать только в одной базе данных, вы могли бы использовать какое-либо поле состояния, чтобы указать бизнес-статус заказа (Получено, Подтверждено, Оплачено ...), а также использовать транзакции для обеспечения согласованности ваших данных.
При таком количестве параметров пришло время рассмотреть шаблон 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 , но я не Я не могу его процитировать.)
Вы можете решить, когда достаточно, и использовать Ввести объект параметра для своего конструктора (или любого другого). другой метод в этом отношении).
Я бы предложил найти зависимости между параметрами, а затем создать структуры или иные классы, чтобы сохранить их и передать их вашему конструктор, а не куча вещей, которые на первый взгляд не кажутся связанными.
Мне нужно было бы больше узнать о том, что делает класс и каковы параметры, но есть вероятность, что у класса слишком много обязанностей. Можно ли разделить класс на более мелкие независимые классы?
Использование установщиков не решает проблему класса, имеющего много зависимостей / параметров. Он просто перемещает проблему в другое место и не заставляет вводить параметры.
Что касается методов, я стараюсь следовать совету из книги «Чистый код», чтобы иметь не более 3 параметров на метод (IIRC). Для конструкторов у меня может быть больше параметров, потому что обычно конструктор будет вызываться моей структурой внедрения зависимостей, а не мной.
Шаблон строителя, упомянутый mmyers, также является хорошим решением при строительстве сложных объектов, и нет способа сделать их менее сложными.
Обычно я бы сказал, что не более пяти, из правила 7 +/- 2 на короткий срок память и некоторый пессимизм в отношении внимания программистов. Примечание: я бы посчитал список varargs как одну сущность.
Если вы действительно вынуждены создавать объект за один раз, вы обычно можете собирать связанные параметры в объектах простых значений и передавать их в конструктор. Постарайтесь убедиться, что объекты-значения имеют некоторый концептуальный смысл, а не просто случайные наборы информации ...
Code Complete 2 рекомендует довольно разумный предел семи параметров для любого метода.
Попробуйте установить разумные значения по умолчанию для некоторых членов. Это позволит вам использовать getter / setters, не беспокоясь о том, что характеристика неполна.
Не думаю, что вы можете сказать, что подходящим числом является «семь, не более» или «пять».
Хорошим эмпирическим правилом для конструкторов является передача объекта с его идентичностью , а не с его состоянием . Те параметры, которые вы передаете, являются теми, которые необходимы для существования объекта и без которых большинство операций объекта могут быть невозможны.
Если у вас действительно есть класс с очень сложной естественной идентичностью, следовательно, требующий много параметров затем рассмотрим дизайн вашего класса.
Пример плохого конструктора:
public NightWatchman(int currentFloor, int salary, int hapiness) {...}
Здесь NightWatchman создается с некоторыми значениями по умолчанию, которые почти наверняка изменятся за короткое время. Забавно, что объекту рассказывают об их значениях одним способом, и затем использует их другим способом (через их установщики) в будущем.
Пример лучшего конструктора:
public GateWatchman(Gate watchedGate, boolean shootOnSight) {...}
Ворота, за которыми наблюдает сторож, - это необходимая информация для существования. В классе я бы отметил закрытый финал . Я решил передать переменную shootOnSight в конструктор, потому что здесь было важно, чтобы объект всегда знал, стрелять ли грабителям. Здесь в качестве типа используется идентификатор.
У меня может быть класс с именами ShootingGateWatchman и PoliceCallingGateWatchman - то есть параметр интерпретируется как часть идентификатора объектов.
Это зависит.
Если некоторые параметры имеют одинаковый тип и могут быть перепутав, я бы допустил довольно небольшое число (скажем, 5).
Если параметры бывают разных типов, поэтому они не могут быть перепутаны, то я допущу еще немного. Десять будут близки к пределу.
Как насчет передачи объекта Param => Value Map в конструктор? Если вызывающая сторона пропускает какие-либо критические параметры, пусть конструктор выбросит исключение.
Это означает, что плохие вызовы конструктора будут перехватываться только во время выполнения, а не во время компиляции, что является недостатком. Но подход геттер / сеттер имеет ту же проблему, и с ним должно быть намного проще работать.