Как удалить дублирование из моего кода

У меня есть два подобных методов. Один из них что-то печатает, а другой что-то сохраняет. Как вы можете видеть есть много повторяющегося кода. Как я должен рефакторинг и убрать это дублирование ?

public static void printSomething(List<String> list) {
    for (String item : list) {
        if (item.contains("aaa")) {
            System.out.println("aaa" + item);
        }
        if (item.contains("bbb")) {
            System.out.println("bbb" + item);
        } else {
            System.out.println(item);
        }
    }
}

public static Map<String, String> getSomething(List<String> list) {
    Map<String, String> map = new HashMap<String, String>();
    for (String item : list) {
        if (item.contains("aaa")) {
            map.put("aaa", item);
        }
        if (item.contains("bbb")) {
            map.put("bbb", item);
        } else {
            //do nothing
        }
    }
    return map;
}

обновление:

код был обновлен для решения проблемы, когда метод не совсем похож

3 ответов


универсальное действие интерфейса, которое имеет действие метода (T t), может уменьшить код.

public interface Action<E> {
        void action(E e);
}

пример:

public static void forEach(List<String> list, Action <String> action) {
    for(String s : list){
           action.action(s);

}

теперь вам просто нужно 2 различные реализации действий.

вы можете использовать аннонимные типы, если вы не хотите создавать класс.

если вы знаете c#, это похоже на lambdas.

edit:

использование анонимной типа:

public static Map<String, String> getSomething(List<String> list) {
    final Map<String, String> map = new HashMap<String, String>();
    forEach(list, new Action<String>() {
        @Override
        public void action(String e) {
            if (e.contains("aaa")) {
                map.put("aaa", e);
            }
            if (e.contains("bbb")) {
                map.put("bbb", e);
            } else {
                // do nothing
            }
        }
    });
    return map;
}

создания класс:

public static Map<String, String> getSomething2(List<String> list) {
    final Map<String, String> map = new HashMap<String, String>();
    forEach(list, new ListToMapAction(map));
    return map;
}


public class ListToMapAction implements Action<String> {

    Map<String, String> map;

    public ListToMapAction(Map<String, String> map) {
        this.map = map;
    }

    @Override
    public void action(String e) {
        if (e.contains("aaa")) {
            map.put("aaa", e);
        }
        if (e.contains("bbb")) {
            map.put("bbb", e);
        } else {
            // do nothing
        }
    }

}

предполагая, в каком порядке println of "aaa" и "bbb" appear не имеет значения, вы можете заменить реализацию printSomething С

public static void printSomething(List<String> list) {
  Map<String, String> map = getSomething(list);
  for(Map.Entry<String, String> entry : map) {
    System.out.println(entry.getKey() + entry.getValue());
  }
}

на языке программирования с первоклассными функциями вы передадите функцию в качестве параметра, указывающего, что вы хотите сделать внутри цикла (например, см. обновление ниже). Java будет иметь lambdas в версии 8, но они не совсем подходят для этой работы.

в текущем состоянии Java вам придется довольствоваться чем - то более уродливым-например, передачей дополнительного параметра методу; или вы можете передать анонимные внутренние классы, которые реализуют интерфейс, но ИМХО это еще уродливее, чем то, что я собираюсь предложить:

static void printSomething(List<String> list, boolean print)

если print is true затем распечатайте внутри цикла, иначе добавьте в Map. Конечно, вам придется добавить пару ifвнутри цикла для проверки этого условия, и в начале, один лишний if чтобы определить, является ли Map должно быть инициализировано. В любом случае, метод возвращает Map, а Map может быть null для случая печати. Это то, что я имею в виду:

static Map<String, String> processSomething(List<String> list, boolean print) {

    Map<String, String> map = null;
    if (!print)
        map = new HashMap<String, String>();

    for (String item : list) {
        if (item.contains("aaa")) {
            if (print)
                System.out.println("aaa" + item);
            else
                map.put("aaa", item);
        }
        if (item.contains("bbb")) {
            if (print)
                System.out.println("bbb" + item);
            else
                map.put("bbb", item);
        } else if (print) {
            System.out.println(item);
        }
    }

    return map;

}

обновление

например, в Python-который позволяет передавать функции в качестве параметров, вот как вы решите проблему элегантным способом:

def processSomething(lst, func):
    result = None
    for item in lst:
        if 'aaa' in item:
            result = func(item, 'aaa', result)
        elif 'bbb' in item:
            result = func(item, 'bbb', result)
        else:
            result = func(item, '', result)
    return result

def printer(item, key, result):
    print key + item

def mapper(item, key, result):
    if not result:
        result = {}
    if key:
        result[key] = item
    return result

посмотреть, как это работает:

processSomething(['aaa', 'bbb', 'ccc'], printer)
=> aaaaaa
   bbbbbb
   ccc

processSomething(['aaa', 'bbb', 'ccc'], mapper)
=> {'aaa': 'aaa', 'bbb': 'bbb'}