[英]Should I use the java Stream.map Function together with an switch statement?
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) (备注:我也不喜欢每次添加新类型时我都需要更新所有的switch语句)
@TimB is correct in its answer . @TimB的答案是正确的。 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 每次添加新类型时,我都要更新所有的switch语句
your "factory lambda" is breaking the Open/closed principle : 你的“工厂lambda”打破了开放/封闭的原则 :
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 : 你可以通过利用java 8功能轻松使用它:
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. switch
的替代方法是使用Map
将值映射到封装所需行为的对象。 Even as this pattern exists for a long time, Java 8 adds new possibilities for implementing it in a straight-forward manner: 即使这种模式存在很长时间,Java 8也为以直接的方式实现它提供了新的可能性:
// 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));
You are right, this sort of switch is almost always an anti-pattern although it's unconnected to the streaming really. 你是对的,这种转换几乎总是一种反模式,尽管它实际上与流媒体没有联系。
The easiest way to fix this is to use a Factory. 解决此问题的最简单方法是使用Factory。 Instead of doing new Bird you do: 而不是做新的鸟你做:
Animals.createAnimal(animal);
and that factory method returns the correct type. 并且该工厂方法返回正确的类型。
You may still need a switch inside the factory but at least it's encapsulated away and only in one place in the code. 你可能仍然需要在工厂内部使用一个开关,但至少它被封装起来并且只在代码中的一个地方。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.