I want to transfer a stream of objects to different objects depending on a type. For example :
Stream<Animal> animals = Arrays.stream(Arrays.asList(new Animal("A"),new Animal("B")));
Stream result = animals.map(animal) ->{
switch (animal.getType()) {
case "A" : return new Bird(animal);
case "B" : return new LION(animal);
case "C" : return new Tiger(animal);
case "D" : return new FISH(animal);
}
}
Is this an functional-programming "anti-pattern"?
Can I achive the above differently with functional programming?
(Remark: I also don't like is that every time I add a new type I have to update all my switch statements)
@TimB is correct in its answer . This is not related to functional programming.
As you stated:
every time I add a new type I have to update all my switch statements
your "factory lambda" is breaking the Open/closed principle:
software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification
You could create this animal factory that follows this principle:
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
public class AnimalFactory {
private final Map<String, Function<Animal, Object>> delegateFactories
= new HashMap<String, Function<Animal,Object>>();
public AnimalFactory withFactory(String type, Function<Animal, Object> factory) {
delegateFactories.put(type, factory);
return this;
}
public Object createAnimal(Animal animal) {
return delegateFactories.get(animal.getType()).apply(animal);
}
}
you could them use it easily by taking advantage of java 8 feature:
public static void main(String[] args) {
Stream<Animal> animals = Arrays.asList(new Animal("A"),new Animal("B")).stream();
AnimalFactory animalFactory = new AnimalFactory();
animalFactory.withFactory("A", Bird::new);
animalFactory.withFactory("B", Lion::new);
animalFactory.withFactory("C", Tiger::new);
animalFactory.withFactory("D", Fish::new);
Stream result = animals.map(animalFactory::createAnimal);
}
The alternative to switch
is to use a Map
which maps the values to objects encapsulating the desired behavior. Even as this pattern exists for a long time, Java 8 adds new possibilities for implementing it in a straight-forward manner:
// one-time initialization code
Map<String,Function<Animal,Animal>> factories=new HashMap<>();
factories.put("A", Bird::new);
factories.put("B", Lion::new);
factories.put("C", Tiger::new);
factories.put("D", Fish::new);
// use case
Stream<Animal> animals = Stream.of(new Animal("A"),new Animal("B"));
Stream result = animals.map(a -> factories.get(a.getType()).apply(a));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With