2015-11-09 3 views
8

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

switch(operation) 
case addition : return add(int a, String b, String c); 
case multiply : return multiply(int a, int b); 
case substract : return substract(int a, int b); 

подход 1: с помощью полиморфизм

public interface Operation { 
    void performOperation(int a, int b); 
} 

Затем заполнить карту с имеющимися реализациями:

Map<Key, Operation> actions = new HashMap<>(); 
actions.add(addition, new addOperation()); 
actions.add(multiply, new multiplyOperation()); 
actions.add(substract, new substractOperation()); 

Тогда я могу сослаться когда мне нужно выполнить операцию.

Вопросы, которые я имею с этим подходом является то, что я имею создать большое количество классов/annonymous классов

подход 2: Использование Enum

public enum MyKeyEnum { 
    ADDITION { 
     public void performOperation(int a, int b) { 
      // Perform addition 
     } 
    }, 
    MULTIPLY { 
     public void performOperation(int a, int b) { 
      // Perform Multiplication 
     } 
    }; 

    public abstract void performOperation(int counter, String dataMain, String dataSub); 
    } 

Такой подход на самом деле лучше из двух но я увидел другой eaxmple в Java 8 и хочу использовать что-то вроде этого

как все это после рисунка я пытался использовать функциональный интерфейс и карты

final static Map<String, Supplier<IAction>> map = new HashMap<>(); 
static { 
    map.put("add", Addition::new); 
    map.put("multiply", Multiply::new); 
} 
public static void main(String[] args) throws Exception { 
    Supplier<IAction> action = map.get("add"); 
    System.out.println(action.get().performAction(10,10)); 

    action = map.get("multiply"); 
    System.out.println(action.get().performAction(10,10)); 
} 

Но это опять-таки имеет недостатки первого подхода так хотелось, чтобы увидеть, если я могу использовать лямбды как я использовал реализацию Enum Там есть частичная реализация функции представлены в Java 8, который я хотел бы использовать Пример:

BiFunction<Integer, Integer, Integer> minus = (x, y) -> x - y; 
Function<Integer, Integer> subtractor = partial(minus, 10); 
System.out.println(subtractor.apply(4)); // 6 

в BiFunction принимает только два параметра я создал Trifuction как

@FunctionalInterface 
interface TriFunction<T, U, V, R> { 
    R apply(T a, U b, V c); 
} 

public static <T, U, V, R> Function<V, R> partial(TriFunction<T, U, V, R> f, T x, U y) { 
    return (z) -> f.apply(x, y, z); 
} 

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

Map<String, TriFunction<String, Integer, Integer, Operation>> map 
= new HashMap<>(); 
+0

Что вы хотите сказать? – Flown

+0

Как ваш интерфейс «TriFunction» заменяет переключатель? – Seelenvirtuose

+1

Более простым подходом будет полиморфизм: выполните операцию перечисления и используйте 'operation.perform (a, b, c)'. –

ответ

5

Вы уже здесь. Если у Вас есть метод, который имеет ту же сигнатуру своего интерфейса вы можете также передать его в репозиторий операции, как:

Map<String, IntBinaryOperator> operations = new HashMap<>(); 
operations.put("add", Integer::sum); 
operations.put("subtract", (a, b) -> a - b); 
operations.put("multiply", (a, b) -> a * b); 
//... 
System.out.println(operations.get("multiply").applyAsInt(10, 20)); 
0

Thx для вашего вопроса, как я наткнулся на ту же самую проблему. Я искал способ устранить if if if или switch блоков в моем коде в течение некоторого времени.

Я выбрал Map + Supplier подход, реализованный в рамках завода, как показано в следующем фрагменте:

public class OperatorFactory { 
    private final String supportedOperatorsRegex = "\\+|\\*|-"; 
    private Map<String, Supplier<Operator>> supportedOperators = ImmutableMap.of(
     "+", Addition::new, "*", Multiplication::new, "-", Subtraction::new, "ID", Identity::new 
    ); 

    public Operator parseToOperator(String input) { 
     return supportedOperators.get(extractOperator(input)).get(); 
    } 

    private String extractOperator(String input) { 
     Matcher matcher = Pattern.compile(supportedOperatorsRegex).matcher(input); 

     if (matcher.find()) return matcher.group(); 
     if (input.matches("\\d+")) return "ID"; 

     throw new UnsupportedOperationException("unsupported operation: " + input); 
    } 
} 

Я нахожу это гуманного ближе к Open/Close Принцип (с уплотнительным в ТВЕРДЫХ принципов):

  1. Теперь, все что мне нужно сделать, чтобы расширить функциональные возможности, чтобы добавить еще один класс оператора, который реализует некоторый Operator интерфейс, который я определил в другом месте, добавьте его в supportedOperators карте и в SupportedOperatorsRegex без изменения бизнес-логики класса OperatorFactory.
  2. Кроме того, клиентским классам не нужно знать, что происходит в OperatorFactory, и это меньше связано.
Смежные вопросы