我该如何解决重复代码?

时间:2018-12-10 20:43:06

标签: java

我要检查包装内的所有成分(浇头和馅料)是否都不含素食和坚果。这是我想出的解决方案,但是由于代码重复,我认为它有点低效。有更有效的方法吗?

((我有一张所有浇头和馅料的地图,每个图都包含布尔值,以了解浇头/馅料是否是素食主义者,并且是否不含坚果。

public boolean isVegan() {
    for (Topping t : toppings) {
        if (!t.isVegan()) {
            return false;
        }
    }
    for (Filling f : fillings) {
        if (!f.isVegan()) {
            return false;
        }
    }
    return bread.isVegan();
}

public boolean isNutFree() {
    for (Topping t : toppings) {
        if (!t.isNutFree()) {
            return false;
        }
    }
    for (Filling f : fillings) {
        if (!f.isNutFree()) {
            return false;
        }
    }
    return bread.isNutFree();
}

4 个答案:

答案 0 :(得分:5)

假设Ingredient是这些不同类的基类,并且该类定义了isVegan()方法,则可以从所有这些对象创建一个Stream并计算是否所有都是纯素食主义者:

public boolean isVegan() {
    return 
    Stream.concat(toppings.stream(), fillings.stream(), Stream.of(bread))
          .allMatch(Ingredient::isVegan);

}

对于isNutFree(),想法是相同的:

public boolean isNutFree() {
    return 
    Stream.concat(toppings.stream(), fillings.stream(), Stream.of(bread))
          .allMatch(Ingredient::isNutFree);

} 

请注意,您还可以推广匹配方法以进一步减少重复:

public boolean allMatch(Predicate<Ingredient> predicate) {
    return 
    Stream.concat(toppings.stream(), fillings.stream(), Stream.of(bread))
          .allMatch( i -> predicate.test(i));

} 

并使用它,例如:

boolean isNutFree = allMatch(Ingredient::isNutFree);
boolean isVegan =  allMatch(Ingredient::isVegan);

答案 1 :(得分:2)

这是一种可以代替馅料或馅料或其他任何食物的食物类型:

public interface FoodPart {

    boolean isVegan();

    boolean isNutFree();

}

在这里,我们有一个包含所有通用代码的抽象Food类:

public abstract class Food {

    private List<? extends FoodPart> foodParts;

    public boolean isVegan() {
        return foodParts.stream().noneMatch(foodPart -> foodPart.isVegan());
    }

    public boolean isNutFree() {
        return foodParts.stream().noneMatch(foodPart -> foodPart.isNutFree());
    }

}

这是具体而非抽象的食物:

public class Lasagne extends Food {}

编辑:

如果您不想继承FoodPart,则可以将List<? extends FoodPart>更改为List<FoodPart>

您还可以使Food不再抽象,以便您可以轻松使用它,并且不要忘记添加getter / setter以提供foodParts

答案 2 :(得分:2)

是的,你们很快:)

我写的内容已经在这里的其他答案中已经涉及到,但由于我的确有一些细微的差异(不一定更好),所以只是发布。而且由于我已经经历了编写代码的动作,所以我不妨将其发布:)

首先是用于馅料和浇头的界面:

public interface FoodInformation {
    boolean isVegan();
    boolean isNutFree();
    boolean isGlutenFree();
}

然后是一个抽象类,您的浇头和馅料可以扩展:

public abstract class Ingredient implements FoodInformation {
    private boolean vegan;
    private boolean nutFree;
    private boolean glutenFree;

    public Ingredient(boolean vegan, boolean nutFree, boolean glutenFree) {
        this.vegan = vegan;
        this.nutFree = nutFree;
        this.glutenFree = glutenFree;
    }

    @Override
    public boolean isVegan() {
        return vegan;
    }

    @Override
    public boolean isNutFree() {
        return nutFree;
    }

    @Override
    public boolean isGlutenFree() {
        return glutenFree;
    }
}

您的馅料:

public class Filling extends Ingredient {
    public Filling(boolean vegan, boolean nutFree, boolean glutenFree) {
        super(vegan, nutFree, glutenFree);
    }
}

您的浇头:

public class Topping extends Ingredient {
    public Topping(boolean vegan, boolean nutFree, boolean glutenFree) {
        super(vegan, nutFree, glutenFree);
    }
}

还有你的包裹:

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class Wrap {
    private List<Filling> fillings;
    private List<Topping> toppings;

    public Wrap(List<Filling> fillings, List<Topping> toppings) {
        this.fillings = fillings;
        this.toppings = toppings;
    }

    public boolean isNutFree() {
        return testIngredient(FoodInformation::isNutFree);
    }

    public boolean isVegan() {
        return testIngredient(FoodInformation::isVegan);
    }

    public boolean isGlutenFree() {
        return testIngredient(FoodInformation::isGlutenFree);
    }

    private boolean testIngredient(Predicate<FoodInformation> predicate) {
        // edited thanks to davidxxx for the Stream.concat notation!
        return Stream
                .concat(fillings.stream(), toppings.stream())
                .allMatch(predicate);
    }
}

并通过一个测试来展示实现的方法:

import org.junit.Before;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collections;

import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertFalse;

public class WrapTest {
    private Wrap wrap;

    @Before
    public void setup() {
        Filling filling1 = new Filling(true, true, false);
        Filling filling2 = new Filling(true, false, true);
        Filling filling3 = new Filling(true, true, true);

        Topping topping1 = new Topping(true, true, true);

        wrap = new Wrap(Arrays.asList(filling1, filling2, filling3), Collections.singletonList(topping1));
    }

    @Test
    public void testIsGlutenFree() {
        assertFalse(wrap.isGlutenFree());
    }

    @Test
    public void testIsNutFree() {
        assertFalse(wrap.isNutFree());
    }

    @Test
    public void testIsVegan() {
        assertTrue(wrap.isVegan());
    }
}

玩得开心吧!

答案 3 :(得分:1)

创建一个具有isVegan和isNutFree的接口

UITextView

然后您的每个类都将实现您的界面

public interface MyInterface {
    boolean isVegan();
    boolean isNutFree();
}

接下来创建一种可以测试列表的方法

public class Topping implements MyInterface {

    @Override    
    public boolean isVegan() {
       return isVegan;
    }

    @Override boolean isNutFree() {
        return isNutFree;
    }
}

public class Filling implements MyInterface {

    @Override    
    public boolean isVegan() {
       return isVegan;
    }

    @Override boolean isNutFree() {
        return isNutFree;
    }
}

然后您可以将每个列表传递给方法以获取结果