披萨店小程序
问题陈述
我们需要为一家披萨公司构建软件,该公司想要准备不同类型的披萨,例如鸡肉披萨,扁平面包,意大利辣香肠披萨和额外的奶酪,并在上面放些配料。
让我们尝试看看哪种设计模式适合该问题说明以及在哪种情况下。 传统上,对于披萨问题,最常用的是构造器模式。 但是,也有一些使用装饰器的示例,两种方法都是正确的,但用例有所不同。 Builder是一种对象创建模式,而装饰器用于在运行时更改已构建的对象。让我们尝试通过示例来理解这一点:
-
生成器模式:
这里的用例是按照既定规格一次性制作披萨。
让我们来看看披萨课:
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); } }
-
装饰图案:
装饰器模式用于动态添加或删除对象的其他功能或职责,而不会影响原始对象。 用例是先准备一些基础比萨,然后再添加不同的规格。
在这里,我们需要一个要装饰的BasicPizza(混凝土组件)的接口(Pizza)和一个包含Pizza(已装饰)接口的引用字段的PizzaDecorator类。
披萨界面:
public interface Pizza { public String bakePizza(); public float getCost(); }
基本比萨实施:
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 Mashroom 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)之类的模式。 装饰器之类的模式(也称为结构设计模式)用于可扩展性或为已创建的对象提供结构更改。
两种类型的模式在很大程度上都偏重于组合而不是继承,因此将其作为使用builder而不是decorator的区分因素没有任何意义。 两者都在运行时给出行为,而不是继承它。
因此,如果要限制具有某些属性/功能的对象创建,则应使用builder。 例如,在创建对象之前必须设置4-5个属性,否则我们将冻结对象创建直到尚未设置某些属性。 基本上,使用它代替构造函数-正如Joshua Bloch在Effective Java,2nd Edition中指出的那样。 构建器公开了生成的对象应具有的属性,但隐藏了如何设置它们。
装饰器用于添加现有对象的新功能以创建新对象。 在添加对象的所有功能之前,没有冻结对象的限制。 两者都使用合成,因此它们看起来相似,但是在用例和意图上有很大不同。
另一种方法是使用工厂模式。 如果我们不想公开这些属性,而是希望“神奇地”在内部创建某些披萨,则可以基于某些属性。 我们将在后面的文章中使用Factory Pattern探索该实现。
翻译自: https://www.javacodegeeks.com/2014/08/pizza-problem-builder-vs-decorator.html
披萨店小程序