Behavior Parameterization
Tags: java
Published: 2023-04-11 07:37:57

One of the simplest ways to improve code is to pass behavior as a parameter to a method. Business requirements change every time and so our code needs to adapt. Take a look at the code below to see how we can introduce behavior parameterization to achieve maintainability and flexibility to our code. 

Let’s say we have two requirements.
1. Filter green apples from the list of apples.
2. Filter apples by its weight.

```java
public List<Apple> filterApplesByColor(List<Apple> inventory, String color){
	List<Apple> result = new ArrayList<>();
	for(Apple apple: inventory){
		if(apple.getColor().equals(color)){
			result.add(apple);
		}
	}
	return result;
}

public List<Apple> filterApplesByWeight(List<Apple> inventory, int weight){
	List<Apple> result = new ArrayList<>();
	for(Apple apple: inventory){
		if(apple.getWeight() > weight){
			result.add(apple);
		}
	}
	return result;
}


List<Apple> greenApples = filterApplesByColor(inventory, "green");
List<Apple> heavyApples = filterApplesByWeight(inventory, 150);

```

Notice how are we duplicating the code here. The two methods have the same code, only the difference is the condition statement inside of it. What happens if there are additional requirements such as filtering by size, shape or its origin? We will end up on a lot of duplicate codes which violate the DRY (Don’t repeat yourself) principle.


By using behavior parameterization, we instead focusing on the condition statement rather than creating their own dedicated method. Sounds complex but it is so easy to implement. To achieve it, first we need to create an interface.

```java
public interface ApplePredicate{
    boolean isValid(Apple apple);
}
```

Then we will create a method that instead of hard coding the condition statement inside of it, we will rather pass the above interface as parameter.

```java
public List<Apple> filterApples(List<Apple> inventory, ApplePredicate applePredicate){
    List<Apple> result = new ArrayList<>();
    for(Apple apple: inventory){
        if(applePredicate.isValid(apple)){
            result.add(apple);
        }
    }
    return result;
}

```

In order to use the filterApples method, we will use anonymous class. Of course, we can create a new class instead but that defeats the purpose of maintainability as creating one class per condition is too much for this kind of scenario.

```java
List<Apple> greenApples = filterApples(inventory, new ApplePredicate() {
    public boolean isValid(Apple apple){
        return apple.getColor().equals("green"); 
    }
});

List<Apple> heavyApples = filterApples(inventory, new ApplePredicate() {
    public boolean isValid(Apple apple){
        return apple.getWeight() > 150; 
    }
});

```
Our code becomes simpler. We are reusing the same method whatever filter requirements we may want. Filter by shape or origin? Just pass the condition!



But we still have one problem. I don’t know about you but using anonymous class is too verbose for me. We can shorten our code using lambda. If you don’t know lambda yet, don’t worry I will create a separate article about it. For now, think of lambda as sweet syntax for anonymous class that contains only one method (which is applicable to our scenario).

The only changes that we need is to add an @FunctionalInterface annotation in our interface. 

```java
@FunctionalInterface
public interface ApplePredicate{
    boolean isValid(Apple apple);
}

public List<Apple> filterApples(List<Apple> inventory, ApplePredicate applePredicate){
    List<Apple> result = new ArrayList<>();
    for(Apple apple: inventory){
        if(applePredicate.isValid(apple)){
            result.add(apple);
        }
    }
    return result;
}

```
Then we can change the anonymous class into lambda.

```java
List<Apple> greenApples = filterApples(inventory, () -> apple.getColor().equals("green"));

List<Apple> heavyApples = filterApples(inventory, () -> apple.getWeight() > weight; );

```

Now, we have created a more maintainable and flexible code using behavior parameterization. Next time we add another filter, we will not create a method or a class. Just pass the condition of what we want, and it will be given to us. Pretty cool, right?