Подскажите, как в моем случае оптимизировать код Java и убрать из него дублирующиеся участки?

Рейтинг: 3Ответов: 2Опубликовано: 27.03.2023

Ситуация, есть класс и методы в нем:

public class MyClass {
    public MyClass {...}

    public ... method1(...) {
       ...
       while(...) {
          ...
          for(...) {
             method4(...);
          }
       }
    }

    public ... method2(...) {
       ...
       while(...) {
          ...
          for(...) {
             method5(...);
          }
       }
    }

    public ... method3(...) {
       ...
       while(...) {
          ...
          for(...) {
             method6(...);
          }
       }
    }

    public ... method4(...) {...}

    public ... method5(...) {...}

    public ... method6(...) {...}
}

Код в методах 1, 2 и 3 совпадает, кроме вызова методов 4, 5 и 6 внутри циклов.

Вопрос, можно ли как-то совпадающий код объединить в рамках одного метода и просто его вызывать внутри методов 1, 2, 3 с передачей внутрь, соответственно, других методов (4, 5 и 6, в данном случае)? Просто передавать метод, как параметр, нельзя, насколько я знаю. Других идей, как красиво это сделать у меня тоже пока нет. Подскажите, пожалуйста.

Ответы

▲ 3Принят

Если методы metod4, metod5, metod6 требуют разных параметров и не могут быть сведены к какому то одному типу функции, проще сделать некий токен и передавать соответствующее значение из вызывающих методов в общий метод, в котором будет использоваться switch:

enum Token{T1, T2, T3;}

public void m1() {
    common(Token.T1);
}

public void m2() {
    common(Token.T2);
}

public void m3() {
    common(Token.T3);
}

private void common(Token t) {
    // ...
    while (...) {
        for (...) {
            switch(t) {
                case T1: m4(p1, p2); break;
                case T2: m5(p1); break;
                case T3: m6(p1, p2, p3); break;
            }
        }
    }
}

private void m4(int p1, String p2) {}
private void m5(Integer p1) {}
private void m6(Object ... arr) {}

Если же упомянутые функции можно свести к некоему общему типу относительно возвращаемого типа и типов входных параметров, то можно определить свой функциональный интерфейс или использовать существующий и передавать ссылки на соответствующие методы.

Пример с IntBinaryOperator

public void m1() {
    common(this::sum);
}

public void m2() {
    common(this::min);
}

public void m3() {
    common(this::mul);
}

private void common(IntBinaryOperator op) {
    for (int i = 0; i < 100; i++) {
        for (int j = i; j < 100; j++) {
            System.out.println(op.applyAsInt(i, j));
        }
    }
}

private int sum(int x, int y) { return x + y;}
private int min(int x, int y) { return Math.min(x, y);}
private int mul(int x, int y) { return x * y;}

Пример с собственной функцией:

@FunctionalInterface
interface MyFun<T1, T2, T3> {
    void use(T1 t1, T2 t2, T3 t3);
}

public void m1() {
    common(this::f4);
}

public void m2() {
    common(this::f5);
}

public void m3() {
    common(this::f6);
}

private void common(MyFun<Integer, String, Double> op) {    
    for (int i = 0; i < 100; i++) {
        for (int j = i; j < 100; j++) {
            op.use(j, String.valueOf(i), Math.sqrt(i * j));
        }
    }
}

private void f4(int i, String s, double d) {}
private void f5(Integer i, String s, Double d) {}
private void f6(Integer i, String s, double d) {}
▲ 2

Можно (как в комментарии вам написали) передавать методы в качестве аргументов.

Вот пример того, как в метод передаётся метод, требующий строку в качестве аргумента и возвращающий строку:

import java.util.function.Function;

public class MyClass {
    
    public static void main(String args[]) {
      MyClass myClass = new MyClass();
      myClass.test(myClass::test1);
    }
    
    void test(Function<String, String> arg){
        String result = arg.apply("value");
         System.out.println(result);
    }
    
    String test1(String arg){
        System.out.println(arg);
        return arg+1;
    }
}

Выведется

value
value1