使用Java 8

时间:2016-07-28 07:11:06

标签: design-patterns functional-programming java-8

Wikipedia在这里有一个装饰模式的例子:

https://en.wikipedia.org/wiki/Decorator_pattern#Second_example_.28coffee_making_scenario.29

我试图使用Java 8解决这个问题,我提出了解决方案:

1.CoffeeDecorator.java

public class CoffeeDecorator {

public static Coffee getCoffee(Coffee basicCoffee, Function<Coffee, Coffee>... coffeeIngredients) {

    Function<Coffee, Coffee> chainOfFunctions = Stream.of(coffeeIngredients)
                                                      .reduce(Function.identity(),Function::andThen);
    return chainOfFunctions.apply(basicCoffee);
}

public static void main(String args[]) {

    Coffee simpleCoffee = new SimpleCoffee();
    printInfo(simpleCoffee);

    Coffee coffeeWithMilk = CoffeeDecorator.getCoffee(simpleCoffee, CoffeeIngredientCalculator::withMilk);
    printInfo(coffeeWithMilk);

    Coffee coffeeWithWSprinkle = CoffeeDecorator.getCoffee(coffeeWithMilk,CoffeeIngredientCalculator::withSprinkles);       
    printInfo(coffeeWithWSprinkle);

}

public static void printInfo(Coffee c) {
    System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
}

}

2.CoffeeIngredientCalculator.java

public class CoffeeIngredientCalculator {

public static Coffee withMilk(Coffee coffee) {
    return new Coffee() {

        @Override
        public double getCost() {
            return coffee.getCost() + 0.5;
        }

        @Override
        public String getIngredients() {
            return coffee.getIngredients() + " , Milk";
        }
    };
}

public static Coffee withSprinkles(Coffee coffee) {
    return new Coffee() {

        @Override
        public double getCost() {
            return coffee.getCost() + 0.2;
        }

        @Override
        public String getIngredients() {
            return coffee.getIngredients() + " , Sprinkles";
        }
    };
}

}

现在,我对CoffeeIngredientCalculator中的解决方案并不那么信服。如果我们在Coffee界面中有一个责任,getCost(),使用功能样式并应用装饰器模式似乎更好,更清洁。它基本上归结为Function<Double,Double>,我们不需要抽象类,单独的装饰器,只能链接函数。

但是在咖啡示例中,对于Coffee对象的成本和描述有两种行为,我并不相信这是一个重要的增值,因为我们正在创建一个匿名类,覆盖了2个方法。

问题:

1)这个解决方案是否可以接受?

2)如果没有,是否有更好的方法使用功能样式来解决它?

3)在我们正在装饰的对象有多种方法的场景中,我们是否应该遵循通常的GOF方式来设置抽象类和单独的装饰器类?

2 个答案:

答案 0 :(得分:3)

所以,快速回答:

  1. 是的,这是可以接受的
  2. 虽然您可以独立装饰/配置Coffee方法。取决于您的要求。由于Coffee不是一个功能接口,即具有多个方法,因此您必须回到普通的旧子类。
  3. 不,你不必按字面意思跟随GoF。无论如何,他们描述了不止一种替代方案。
  4. 最后一点:如果您不喜欢匿名课程,那么您可以编写private static内部课程,或者其他任何内容。一个更紧凑,另一个用垃圾收集器更好。

答案 1 :(得分:2)

您的解决方案是可以接受的。

出于实际原因,例如hashCodetoStringreturn new Coffee(coffee.getCost() + 0.2, coffee.getIngredients() + ", Sprinkles"); 的单一实施,我会用

替换匿名类

构造

return coffee(coffee.getCost() + 0.2, coffee.getIngredients() + ", Sprinkles");

工厂方法

return coffee
    .withCost(coffee.getCost() + 0.2) //new instance
    .withIngredients(coffee.getIngredients() + ", Sprinkles"); //another new instance

甚至复制方法(如immutables

highlight_text()