Java 8 - behavior parameterization

Posted by iBuddy on Thu, 07 Nov 2019 10:54:27 +0100

Preface:

The following content comes from the book java8 practice. I will sort out the contents learned in the book, so as to make it convenient for busy little friends to get started quickly and practice java8

Text:

Suppose an apple farmer has harvested a garden of apples, and he needs you to select satisfactory apples according to his conditions

First, let's create an Apple class

public class Apple {
    
    /**
     * weight
     */
    private Integer weight;
    
    /**
     * colour
     */
    private String color;
   
   getter();
   setter();
   toString();
   ...
}

He said: I need to pick out the red apples

public void filterRedApple(List<Apple> appleList){
        for(Apple apple : appleList){
            if("red".equals(apple)){
                System.out.println("Red apple");
            }
        }
    }    

He said: I want to pick out the green apples

Just think about it. Let's take color as a parameter

    public void filterGreenApple(List<Apple> appleList , String color) {
        for (Apple apple : appleList) {
            if (color.equals(apple)) {
                System.out.println("Green apple");
            }
        }
    }

He said: I need to pick out 150g apples

    public void filterWeightApple(List<Apple> appleList,Integer weight) {
        for (Apple apple : appleList) {
            if (apple.getWeight() > weight) {
                System.out.println("Weight over 150 g Apple");
            }
        }
    }

He said: I want to pick out more than 100g of red apples

    public void filterAppleByWeightAndColor(List<Apple> appleList,String color,Integer weight){
        for (Apple apple : appleList) {
            if (apple.getWeight() > weight && color.equals(apple.getColor())) {
                System.out.println("Weight greater than 100 g Red apple");
            }
        }
    }

In the face of endless demand changes, we need to constantly adapt

Let's see how to improve

Create a new Apple filter interface

public interface ApplePredicate {
    
    /**
     * Screening apples
     */
    boolean test(Apple apple);
    
}

Then we implement the screening method separately

Filter by color

public class FilterRedApple implements ApplePredicate {

    @Override
    public boolean test(Apple apple) {
        return "red".equals(apple.getColor()) ? true : false;
    }

}

Filter by weight

public class FilterWeightApple implements ApplePredicate {

    @Override
    public boolean test(Apple apple) {
        return apple.getColor() > 100 ? true : false;
    }

}

Filter by color and weight

public class FilterAppleByColorAndWeight implements ApplePredicate {

    @Override
    public boolean test(Apple apple) {
        return "red".equals(apple.getColor()) && apple.getWeight > 100 ? true : false;
    }

}

For example, he wants red apples

Let's do this for him

    public static void filterApple(List<Apple> appleList , ApplePredicate p) {
        for (Apple apple : appleList) {
            if (p.test(apple)) {
                System.out.println("This is the apple you want" + apple.toString());
            }
        }
    }

When we call, just pass in its implementation class

    public static void main(String[] args) {
        filterApple(appleList, new FilterRedApple());
        filterApple(appleList, new FilterWeightApple());
    }

Let's look at the difference between the current method and the original method:

The original method is to write a new method to implement each requirement, so that the code will be very cumbersome and redundant, because they are actually doing the same thing: screening the desired apple, just under different conditions

Our improved method is: write a filter interface, and then implement the interface separately. For example, if you want a red apple, write an implementation of sun selected red apple, and if you want a big apple, write a new implementation

It's kind of like a strategic model

Well. We've done a cool thing: the behavior of the fliterApple method depends on the code we pass through the ApplePredicate object. This is behavior parameterization, which can help us write flexible API s

Now, some students may ask me if it is too troublesome to write a new implementation class for each new requirement. We can use anonymous classes to implement it

Indeed, we can use anonymous classes to implement

    public static void main(String[] args) {       
     
    filterApple(appleList,
new ApplePredicate() {
       @Override
public boolean test(Apple apple) { return "red".equal(apple.getColor) ? true : false; } });
}

Although anonymous classes improve the verbosity of writing several implementation classes for an interface to some extent, they still need to create an object specific implementation method to define a new behavior

So, I prefer to use the form of behavior parameterization

Concept:

Behavior parameterization: the ability of a method to accept multiple different behaviors as parameters and use them internally to complete different behaviors

Behavior parameterization can make the code better adapt to the changing needs and reduce the workload in the future

Passing code: passing a new behavior as a parameter to a method

Topics: Java