#java #reflection #factory #checkstyle #cyclomatic-complexity
Вопрос:
Я разрабатываю модуль проверки. Он содержит 100 кодов ошибок(т. е. errcd_01, errcd_02,..,errcd_100), подлежащих проверке. При вводе я получаю конкретный код ошибки(т. Е. errcd_01) из более чем 100. Модуль должен выполнить проверку для этого конкретного кода ошибки.
Я использую фабричный шаблон.
/* Interface */
public interface validateErrCd {
void check_errcd();
}
/* Concrete classes implementing the same interface */
public class validateErrCd_01 implements validateErrCd {
@Override
public void check_errcd() {
//business logic related to errcd_01
}
}
public class validateErrCd_02 implements validateErrCd {
@Override
public void check_errcd() {
//business logic related to errcd_02
}
}
.
.
.
public class validateErrCd_100 implements validateErrCd {
@Override
public void check_errcd() {
//business logic related to errcd_100
}
}
/* Factory */
public class ErrorValidationFactory {
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
if(errorCode.equalsIgnoreCase("errcd_01")){
return new validateErrCd_01();
} else if(errorCode.equalsIgnoreCase("errcd_02")){
return new validateErrCd_02();
} ..
.......
else if(errorCode.equalsIgnoreCase("errcd_100")){
return new validateErrCd_100();
}
else {
return null;
}
}
}
/* I am using the Factory to get object of concrete class by passing an specific error code to be validated (i.e. "errcd_01"). */
public class FactoryPatternDemo {
public static void main(String[] args) {
ErrorValidationFactory errorFactory = new ErrorValidationFactory();
//get an object of validateErrCd_01 and call its check_errcd method.
validateErrCd errcd01 = errorFactory.getValidation("errcd_01");
//call check_errcd method of validateErrCd_01
errcd01.check_errcd();
}
}
Теперь из — за нескольких ошибок if/else внутри Factory класса ErrorValidationFactory я получаю пару ошибок CI/CD при выполнении чистой установки mvn.
например, [Длина метода] — стиль проверки, правило:цикломатическая сложность- PMD.
Итак, есть ли способ, которым я могу заменить, если/иначе, процесс принятия решений в случае переключения внутри фабрики, который не вызывает выше ошибок CI/CD в Java?
Примечание : Если возможно, я хотел бы избежать размышлений
Комментарии:
1. Создайте a
Map<String, validateErrCd>
и заполните его записями, напримерvalidators.put("errcd_100", new validateErrCd_100())
, затем.get()
верните свой валидатор по коду.2. @VLAZ, если подумать, это не сработает, потому что 2 вызова с одним и тем же ключом вернут один и тот же экземпляр, что может быть не тем, что нужно OP, судя по показанному ими коду (если, конечно, вы не создадите карту внутри
getValidation
)3. @FedericoklezCulloca, тогда это просто
Map(String, Supplier<validateErrCd>)
сvalidators.put("errcd_100", validateErrCd_100::new)
, верно?4. @VLAZ да, вот что говорит дан1-й ответ (сейчас):)
Ответ №1:
Вы могли бы использовать Map
:
public class ErrorValidationFactory {
private Map<String,Supplier<validateErrCd>> creators=new HashMap<>();
public ErrorValidationFactory(){
creators.put("errcd_100",validateErrCd_100::new);
//Same for others
}
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
return creators.getOrDefault(errorCode,()->null);
}
}
Supplier
это функциональный интерфейс, содержащий метод, возвращающий объект. SomeClass::new
или ()->new SomeClass()
означает, что для этого будет использоваться конструктор класса.
Это позволяет создавать экземпляры позже.
Если вы хотите создать Map
только один раз, вы можете создать его static
и заполнить в статическом инициализаторе.
Однако, если вы действительно хотите динамически получать конструкторы, вам нужно будет использовать отражение.
Комментарии:
1. Поскольку использовался исходный код
equalsIgnoreCase
, эквивалентное решение будет использоватьnew TreeMap<>(String.CASE_INSENSITIVE_ORDER)
вместоnew HashMap<>()
. Хотя спорно, имеет ли здесь смысл сопоставление без учета регистра.2. Вы также можете упростить поиск, чтобы
return creators.getOrDefault(errorCode, () -> null).get();
3. Спасибо @dan1st, это сработало, чтобы избежать правила:цикломатическая сложность — PMD. Однако, поскольку мне все равно придется вводить записи для каждого errcd
creators.put("errcd_100",validateErrCd_100::new);
, это все равно приведет к сбою [MethodLength] — checkstyle. Есть ли способ создать его с помощью цикла, если у меня есть все errcd(в данном случае от 1 до 100), присутствующие в каком-либо списке?4. @Holger, в настоящее время мы можем игнорировать чувствительность к регистру для этого случая.
5. @Data_Geek похоже, что ваши конкретные классы существуют только для реализации метода
validateErrCd
интерфейса и не имеют (изменяемого) состояния. Итак, вам действительно нужно создавать ихgetValidation
экземпляры или было бы возможно использовать один элемент для каждого типа? Если это так, просто реализуйте их все какenum
тип, и вы получите возможность перечислять их (и даже искать их по имени) бесплатно.