JavaRush /Java 博客 /Random-ZH /比萨店的问题。建造者与装饰者。
CynepHy6
第 34 级
Великий Новгород

比萨店的问题。建造者与装饰者。

已在 Random-ZH 群组中发布

问题描述。

我们需要写一个程序。对于想要准备不同类型披萨的披萨店:鸡肉披萨、美式披萨、肉类披萨、夏威夷披萨、意大利辣香肠披萨等。我们看看哪个模板、什么场景适合解决这个问题。传统上,Builder 模板用于解决“披萨问题”。还有使用Decorator模式的例子,两种模式都是正确的,但使用上有差异。Builder 是用于创建对象的模板,而 Decorator 用于动态修改已完成的对象。 让我们尝试通过示例来理解这一点:

1. 模板生成器:

在这种情况下,披萨是一次性用所有原料准备好的。
披萨类:
public class Pizza{ private float totalPrice = 0; private Size size; private Topping topping; private Crust crust; private Cheese cheese; public Size getSize(){ return size; } public void setSize(Size size){ this.size = size; } public Topping getTopping(){ return topping; } public void setTopping(Topping topping){ this.topping = topping; } public Crust getCrust(){ return crust; } public void setCrust(Crust crust){ this.crust = crust; } public Cheese getCheese(){ return cheese; } public void setCheese(Cheese cheese){ this.cheese = cheese; } public float getTotalPrice(){ return totalPrice; } public void addToPrice(float price){ this.totalPrice = totalPrice + price; } }
4个枚举类:
public enum Cheese { AMERICAN{ public float getCost(){ return 40; } }, ITALIAN { public float getCost(){ return 60; } }; public abstract float getCost(); } public enum Crust { THIN{ public float getCost(){ return 70; } } , STUFFED{ public float getCost(){ return 90; } }; public abstract float getCost(); } public enum Size { MEDIUM { public float getCost() { return 100; } }, LARGE { public float getCost() { return 160; } }; public abstract float getCost(); } public enum Topping { PEPPERONI { public float getCost(){ return 30; } }, CHICKEN{ public float getCost(){ return 35; } }, MUSHROOM{ public float getCost(){ return 20; } }; public abstract float getCost(); }
PizzaBuilder 类:
public class PizzaBuilder { Pizza pizza = new Pizza(); public PizzaBuilder withTopping(Topping topping) { pizza.setTopping(topping); pizza.addToPrice(topping.getCost()); return this; } public PizzaBuilder withSize(Size size) { pizza.setSize(size); pizza.addToPrice(size.getCost()); return this; } public PizzaBuilder withCrust(Crust crust) { pizza.setCrust(crust); pizza.addToPrice(crust.getCost()); return this; } public Pizza build() { return pizza; } public double calculatePrice() { return pizza.getTotalPrice(); } }
班级测试:
public class PizzaBuilderTest { @Test public void shouldBuildThinCrustChickenPizza(){ Pizza pizza = new PizzaBuilder().withCrust(Crust.THIN).withTopping(Topping.CHICKEN).withSize(Size.LARGE).build(); assertEquals(Topping.CHICKEN,pizza.getTopping()); assertEquals(Size.LARGE,pizza.getSize()); assertEquals(Crust.THIN,pizza.getCrust()); assertEquals(265.0,pizza.getTotalPrice(),0); } }

2.装饰器模板:

装饰器模式用于动态地向对象添加或删除附加功能,而不影响原始对象。当先准备一些披萨底料,然后添加各种配料时使用。这里我们需要一个要装饰的 BasePizza(基本组件)的接口(Pizza)和一个实际实现该接口的 PizzaDecorator 类。
披萨界面:
public interface Pizza { public String bakePizza(); public float getCost(); }
BasePizza 中的实现:
public class BasePizza implements Pizza{ public String bakePizza() { return "Basic Pizza"; } public float getCost(){ return 100; } }
PizzaDecorator 类:
public class PizzaDecorator implements Pizza { Pizza pizza; public PizzaDecorator(Pizza newPizza) { this.pizza = newPizza; } public String bakePizza() { return pizza.bakePizza(); } @Override public float getCost() { return pizza.getCost(); } }
2 个装饰器:蘑菇和意大利辣香肠
public class Mushroom extends PizzaDecorator { public Mushroom(Pizza newPizza) { super(newPizza); } @Override public String bakePizza() { return super.bakePizza() + " with Mushroom Topings"; } @Override public float getCost() { return super.getCost()+80; } } public class Pepperoni extends PizzaDecorator { public Pepperoni(Pizza newPizza) { super(newPizza); } @Override public String bakePizza() { return super.bakePizza() + " with Pepperoni Toppings"; } @Override public float getCost() { return super.getCost()+110; } }
班级测试:
public class PizzaDecoratorTest { @Test public void shouldMakePepperoniPizza(){ Pizza pizza = new Pepperoni(new BasePizza()); assertEquals("Basic Pizza with Pepperoni Toppings",pizza.bakePizza()); assertEquals(210.0,pizza.getCost(),0); } }

差异

诸如 Builder 和 Factory(以及 Abstract Factory)之类的模式用于创建新对象。诸如装饰器(也称为结构设计模式)之类的模式用于可扩展性或为已创建的对象提供结构更改。两种类型的模式主要通过继承来促进组合,并且差异不足以保证使用构建器而不是装饰器。两者在执行时都会给出自己的行为,而不是继承它。在一种情况下,如果我们想限制具有某些属性/功能的对象的创建,最好使用构建器。例如,在创建对象之前必须设置 4-5 个属性,或者我们希望冻结对象的创建,直到设置某些属性为止。简而言之,使用它而不是构造函数 - 正如 Joshua Bloch 在《Java:有效编程》第二版中所写。构建器提供了生成的对象应具有的属性,但隐藏了如何设置它们。装饰器用于在基于现有对象创建新对象时向现有对象添加新属性。在添加对象的所有功能时,冻结对象没有任何限制。两个模板都使用合成并且可能看起来相似。主要区别在于它们的用途。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION