JetBrains Academy: Strategy - Kamil-Jankowski/Learning-JAVA GitHub Wiki

JetBrains Academy: Strategy

Max and Min:

Use the strategy pattern to implement algorithms to find max and min values in a given array. The basic structure of the provided classes is described below: your job is to complete it.

The class Finder represents the general finding algorithm itself. It works according to the specified strategy.

The interface FindingStrategy provides two methods to write new concrete finding strategies: takeOne to get the next value and getDefaultValue to return a value if nothing was found (the given array is empty). Strategies define only the specific details of the finding algorithm.

Please, do not change the interface FindingStrategy, and do not rename the existing methods.

If the array is empty, the Finder should return: Integer.MAX_VALUE in case of finding the min value, Integer.MIN_VALUE in case of finding the max value.

class Finder {

    private FindingStrategy strategy;

    public Finder(FindingStrategy strategy) {
        this.strategy = strategy;
    }

    /**
     * It performs the search algorithm according to the given strategy
     */
    public int find(int[] numbers) {
        int currentExtremeValue = this.strategy.getDefaultValue();
        if (numbers.length > 0) {
            if (numbers.length > 1) {
                for (int i = 1; i < numbers.length; i++) {
                    int temp = this.strategy.takeOne(numbers[i-1], numbers[i]);
                    if(this.strategy.getClass().equals(MinFindingStrategy.class)) {
                        currentExtremeValue = temp < currentExtremeValue ? temp : currentExtremeValue; // for minimum
                    }
                    if(this.strategy.getClass().equals(MaxFindingStrategy.class)) {
                        currentExtremeValue = temp > currentExtremeValue ? temp : currentExtremeValue; // for maximum
                    }
                }
            } else {
                currentExtremeValue = numbers[0];
            }
        }
        return currentExtremeValue;
    }
}

interface FindingStrategy {

    /**
     * Returns one of two values
     */
    int takeOne(int elem1, int elem2);

    /**
     * Returns the default value of a concrete implementation
     */
    int getDefaultValue();
}

class MaxFindingStrategy implements FindingStrategy {

    public int takeOne(int elem1, int elem2) {
        return elem1 > elem2 ? elem1 : elem2;
    }

    public int getDefaultValue() {
        return Integer.MIN_VALUE;
    }
}

class MinFindingStrategy implements FindingStrategy {

    public int takeOne(int elem1, int elem2) {
        return elem1 < elem2 ? elem1 : elem2;
    }

    public int getDefaultValue() {
        return Integer.MAX_VALUE;
    }
}

Pick your team:

Imagine that you're creating teams to organize events. You need a module for your program that will select the people for these teams.

There are only two selection algorithms:

  • take every k-th person;
  • take the last k people.

In both cases, k > 1.

You decided to use the strategy pattern in the module because new selection algorithms will be added in the future. Also, the pattern allows you to change the current algorithm at runtime.

The basic structure of classes is provided below, but it doesn't really work properly.

Your goal is to implement the following method:

  • setAlgorithm and selectPersons methods of the class SelectionContext;
  • select of the class TakePersonsWithStepAlgorithm to take every k-th person starting with the index 0 in the same order as in the input array (when k is 3, then it must take 0, 3, 6, ... persons);
  • select of the class TakeLastPersonsAlgorithm to take the last k persons in the same order as the input array.

Perhaps, you should add some fields to the classes as well.

Please do not change the class Person and the interface PersonSelectionAlgorithm, and do not rename existing methods.

class SelectionContext {

    private PersonSelectionAlgorithm algorithm;

    public void setAlgorithm(PersonSelectionAlgorithm algorithm) {
        this.algorithm = algorithm;
    }

    public Person[] selectPersons(Person[] persons) {
        return this.algorithm.select(persons);
    }
}

interface PersonSelectionAlgorithm {

    Person[] select(Person[] persons);
}

class TakePersonsWithStepAlgorithm implements PersonSelectionAlgorithm {

    private int step;

    public TakePersonsWithStepAlgorithm(int step) {
        this.step = step;
    }

    @Override
    public Person[] select(Person[] persons) {
        int selectedLength = persons.length % step == 0 ? persons.length/step : persons.length/step + 1;
        Person[] selected = new Person[selectedLength];
        for (int i = 0, j = 0; i < persons.length; i++){
            if (i % step == 0){
                selected[j] = persons[i];
                j++;
            }
        }
        return selected;
    }
}


class TakeLastPersonsAlgorithm implements PersonSelectionAlgorithm {

    private int count;

    public TakeLastPersonsAlgorithm(int count) {
        this.count = count;
    }

    @Override
    public Person[] select(Person[] persons) {
        Person[] selected = new Person[count];
        int startingPoint = persons.length - count;
        for(int i = startingPoint, j=0; i < persons.length; i++, j++){
            selected[j] = persons[i];
        }
        return selected;
    }
}

class Person {

    String name;

    public Person(String name) {
        this.name = name;
    }
}