Рефакторинг большого переключателя в сочетании с предложениями if - PullRequest
2 голосов
/ 24 октября 2019

Итак, у меня что-то вроде этого:

switch (data){
    case "one" :
        if (version1) 
            createDataOneV1();
         else 
             createDataOnetV2();
         break;
    case "two":
        if(version1)
            createDataTwoV1();
        else 
            createDataTwoV2();
        break;
    default:
        createDefaultData();
}

Есть много случаев (переключения). Любые рекомендации по рефакторингу?

Ответы [ 4 ]

1 голос
/ 24 октября 2019

Не использовать Map. Это не даст вам такой же безопасности во время компиляции, как ваша switch.

Если вы все еще хотите от нее избавиться, то я бы предложил использовать enum:

public enum DataCreationStrategy {

    ONE("one", DataCreator::createDataOneV1, DataCreator::createDataOneV2),
    TWO("two", DataCreator::createDataTwoV1, DataCreator::createDataTwoV2)
    // ... other cases
    ;

    private final String key;
    private final Function<DataCreator, String> creator;
    private final Function<DataCreator, String> defaultCreator;

    DataCreationStrategy(String key, Function<DataCreator, String> creator, Function<DataCreator, String> defaultCreator) {
        this.key = key;
        this.creator = creator;
        this.defaultCreator = defaultCreator;
    }

    public static Function<DataCreator, String> of(String key, boolean flag) {
        for (DataCreationStrategy strategy: values()){
            if(strategy.key.equals(key)){
                return flag ? strategy.creator : strategy.defaultCreator;
            }
        }
        return DataCreator::createDefaultData;
    }

}

Затем используйте его следующим образом:

String createdData = DataCreationStrategy.of(key, versionFlag).apply(creator);

(Вы можете заменить String на фактический тип данных, который вам нужно сгенерировать)


Можно реализовать метод ofв моде Stream API также. Но обычный старый цикл for в этом конкретном случае намного чище.

public static Function<DataCreator, String> of(String key, boolean flag) {
   return Arrays.stream(values())
                .filter(s -> s.key.equals(key))
                .findAny()
                .map(s -> flag ? flag ? s.creator : s.defaultCreator )
                .orElse(DataCreator::createDefaultData);
}
1 голос
/ 24 октября 2019

Вы можете создать Key для HashMap с некоторыми Supplier (например):

@RequiredArgsConstructor
class SpecialKey  {
     private final String data;
     private final boolean second;
     // hashCode/equals
}

Предположим, что ваши createDataOneV1 и createDataOneV2 возвращают boolean:

Map<SpecialKey, Supplier<Boolean>> map = new HashMap<>();
map.put(new SpecialKey("one", true), this::createDataOneV1);
map.put(new SpecialKey("one", false), this::createDataOneV2);

А потом просто:

String data = ... // get the "data" somehow
boolean version = ...

boolean res = map.getOrDefault(new SpecialKey(data, version), this::createDefaultData).get();
1 голос
/ 24 октября 2019

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

В любом случае, если вы хотите реорганизовать этот код, вы можете использоватьсистема типов. Определите интерфейс DataCreator, который может генерировать данные для V1 и V2. Вы можете выбрать правильное значение DataCreator, используя функцию, подобную этой:

DataCreator getDataCreatorForData(String data){
    switch(data) {
       case "one": return new DataCreatorOne();
       case "two": return new DataCreatorTwo();
       default: return new DefaultDataCreator()
    }
}

И, получив DataCreator, вы проверяете версию:

DataCreator creator = getDataCreatorForData(data);
if (version1){
    creator.createV1Data();
}else{
    creator.createV2Data();
}

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

1 голос
/ 24 октября 2019

Создание карты со строками в качестве ключей и функциями в качестве значений.

...