Java реинжиниринг двух классов

Требуется реинжиниринг этих двух классов Java, чтобы избежать дублирования кода и повысить удобство сопровождения.

public class Adder {
  public int sum(int[] array) {
    int result = 0;
    for (int i = 0; i < array.length; i++) {
      result += array[i];
    }
  return result;
}

public class Multiplier {
  public int multiply(int[] array) {
    int result = 1;
    for (int i = 0; i < array.length; i++) {
      result *= array[i];
    }
  return result;
}

Обратите внимание на разные result инициализация; это моя главная проблема.

4 ответа

Решение

Я хотел бы опубликовать свой ответ, несмотря на то, что у вопроса уже был хороший ответ (я был слишком медленным). Суть моего решения в том, что он открыт для новых операций, вам не нужно знать имена других функций (поэтому вы можете, например, внедрить ArrayFunction в другие классы):

public abstract class ArrayFuntion {

    public int compute(int[] array) {
        int result = initResult();
        for (int i = 0; i < array.length; i++) {
            result = compute(result, array[i]);
        }
        return result;
    }

    protected abstract int compute(int result, int i);

    protected abstract int initResult();

}


public class Adder extends ArrayFuntion{

    @Override
    protected int compute(int result, int arrayItem) {
        return result + arrayItem;
    }

    @Override
    protected int initResult() {
        return 0;
    }

}


public class Multiplier extends ArrayFuntion {

    @Override
    protected int compute(int result, int arrayItem) {
        return result * arrayItem;
    }

    @Override
    protected int initResult() {
        return 1;
    }

}

Если вы действительно думаете, что это требует некоторого рефакторинга, подумайте об этом:

public class Calculator {
    public int multiply(int[] array) {
        return calculate(1, array, (a, b) -> a * b);
    }

    public int sum(int[] array) {
        return calculate(0, array, (a, b) -> a + b);
    }

    public int calculate(int initValue, int[] array, IntBinaryOperator operator) {
        return Arrays.stream(array).reduce(initValue, operator);
    }

    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        System.out.println(calculator.multiply(new int[]{1, 2, 3, 4}));
        System.out.println(calculator.sum(new int[]{1, 2, 3, 4}));
    }
}

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

public abstract class CommonMath {
    public int calculate(int initialValue, int[] array) {
        int result = initialValue;
        for (int i = 0; i < array.length; i++) {
            result = mathOperation(result, array[i]);
        }
        return result;
    }

    public abstract int mathOperation(int result, int arrayItem);
}

public class Adder extends CommonMath {
    public int sum(int[] array) {
        return calculate(0, array);
    }

    @Override
    public int mathOperation(int result, int arrayItem) {
        return result + arrayItem;
    }
}

public class Multiplier extends CommonMath {
    public int multiply(int[] array) {
        return calculate(1, array);
    }

    @Override
    public int mathOperation(int result, int arrayItem) {
        return result * arrayItem;
    }
}

// test
public static void main(String[] args) {
    try {
        int[] array; {
            array = new int[3];
            array[0] = 1;
            array[1] = 2;
            array[2] = 4;
        }
        System.out.println("sum " + Arrays.toString(array) + " " + new Adder().sum(array));
        System.out.println("multi " + Arrays.toString(array) + " " + new Multiplier().multiply(array));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

выход

sum [1, 2, 4] 7
multi [1, 2, 4] 8

Как насчет

public abstract class Calculator {
   protected int aggregate(int[] array, int startValue) {
       int result = startValue;
       for (int i = 0; i < array.length; i++) {
          result = this.aggregateSingle(array[i], result);
       }
       return result;
    }

    protected abstract int aggregateSingle(int nextValue, int oldAggregation);
}

public class Adder extends Calculator {
   public int sum(int[] array) {
      return this.aggregate(array, 0);
   }
   protected int aggregateSingle(int nextValue, int oldAggregation) {
      return nextValue + oldAggregation;
   }
}

public class Multiplier extends Calculator {
   public int multiply(int[] array) {
      return this.aggregate(array, 1);
   }
   protected int aggregateSingle(int nextValue, int oldAggregation) {
      return nextValue * oldAggregation;
   }
}

Этот подход даже сохраняет структуру классов, что может быть важно в случае, если классы Adder а также Multiplier используются внешне (они public!)

Лично я не считаю всю эту деятельность "улучшением ремонтопригодности" как таковой: она более LoC и еще более сложна из-за этой природы наследования. Мне кажется, что этот вопрос напоминает теоретический вопрос, который должен научить вас, как следует проводить рефакторинг, но точно не учитывает самый важный момент: не усложняйте простые вещи, даже если они могут быть немного излишними.

Другие вопросы по тегам