问题陈述

我们需要为一家披萨公司构建软件,该公司想要准备各种类型的披萨,例如鸡肉披萨,扁平面包,意大利辣香肠披萨和额外的奶酪,并在上面放些配料。

让我们尝试看看哪种设计模式适合该问题说明以及在哪种情况下。 传统上,对于披萨问题,最常用的是构造器模式。 但是,也有一些使用装饰器的示例,两种方法都是正确的,但用例有所不同。 Builder是一种对象创建模式,而装饰器用于在运行时更改已构建的对象。
让我们尝试通过示例来理解这一点:

  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 {@Testpublic 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. 装饰图案:

    装饰器模式用于动态添加或删除对象的其他功能或职责,而不会影响原始对象。 用例是先准备一些基础比萨,然后再添加不同的规格。

    在这里,我们需要一个要装饰的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();}@Overridepublic float getCost() {return pizza.getCost();}
    }

    2个装饰:蘑菇和意大利辣香肠

    public class Mushroom extends PizzaDecorator {public Mushroom(Pizza newPizza) {super(newPizza);}@Overridepublic String bakePizza() {return super.bakePizza() + " with Mashroom Topings";}@Overridepublic float getCost() {return super.getCost()+80;}
    }
    public class Pepperoni extends PizzaDecorator {public Pepperoni(Pizza newPizza) {super(newPizza);}@Overridepublic String bakePizza() {return super.bakePizza() + " with Pepperoni Toppings";}@Overridepublic float getCost() {return super.getCost()+110;}
    }

    测试用例:

    public class PizzaDecoratorTest {@Testpublic 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

比萨问题–建造者与装饰者相关推荐

  1. 分披萨问题_比萨问题–建造者与装饰者

    分披萨问题 问题陈述 我们需要为一家披萨公司构建软件,该公司想要准备不同类型的披萨,例如鸡肉披萨,扁平面包,意大利辣香肠披萨和特制奶酪,并在上面放些配料. 让我们尝试看看哪种设计模式适合该问题说明以及 ...

  2. 披萨店小程序_比萨问题–建造者与装饰者

    披萨店小程序 问题陈述 我们需要为一家披萨公司构建软件,该公司想要准备不同类型的披萨,例如鸡肉披萨,扁平面包,意大利辣香肠披萨和额外的奶酪,并在上面放些配料. 让我们尝试看看哪种设计模式适合该问题说明 ...

  3. 2019 Android 高级面试题总结 从java语言到AIDL使用与原理

    说下你所知道的设计模式与使用场景 a.建造者模式: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 使用场景比如最常见的AlertDialog,拿我们开发过程中举例,比如C ...

  4. 分享Android资深架构师的成长之路,建议收藏

    背景 经常有网友在知乎问答提两个问题:"现在学习移动开发还有前景吗?""开发还有什么可以研究的?".网友回复:"现在还学移动开发?如同49年加入国军! ...

  5. 2021华为Android面试真题解析Android面试题集锦,一文轻松搞定

    前言 19年6月份从网易云音乐离开,放弃了留学机会,开始了人生的第一次创业,前后尝试了两个项目,因为个人能力与时机因素都失败了,虽然没能享受到创业所能够带来高杠杆物质上的回报,但是对个人软技能和自我边 ...

  6. 2019 Android 高级面试题总结

    作者:雨林沐风rzm 链接:https://www.jianshu.com/p/461bf99964ec 声明:本文已获雨林沐风rzm授权发表,转发等请联系原作者授权 说下你所知道的设计模式与使用场景 ...

  7. 2019Android高级面试题总结

    Linux编程点击右侧关注,免费入门到精通! 作者丨雨林沐风rzm https://www.jianshu.com/p/461bf99964ec 说下你所知道的设计模式与使用场景 a.建造者模式: 将 ...

  8. python技术分享

    文章目录 python介绍 应用领域 环境搭建 基础知识 编程工具 变量 基本数据类型 容器数据类型 程序结构 运算符 函数 类 技巧总结 python内存管理 python常用技术 python的缺 ...

  9. 7年老Android一次操蛋的面试经历,附小技巧

    前言 作为一个程序员,如果你在新知识.新技术面前仍一无所知,依然吃着十多年前的老本,那你在知识技术上肯定落伍,如果又未能进入管理层面,那你肯定就会被长江的后浪拍在沙滩上了. 而不少与时俱进.善于学习的 ...

最新文章

  1. SQL Server数据库收缩日志的方法
  2. C语言估算数学常量e,c语言常量的正确表示方法有哪些
  3. 【⌛工欲善其事,必先利其器⏳】葵花宝典の费曼学习法
  4. 停车场管理系统c语言程序,c语言程序设计 停车场管理系统 停车场有1-20个车位号,设计一个停车场管理系统,实现停车场管理...
  5. C++11向线程函数传递参数
  6. 直接裂开!京东二面被问SpringBoot整合MongoDB,我不会啊
  7. C、C++语言中参数的压栈顺序
  8. HTML知识积累及实践(六) - pre,混合框架
  9. Chrome 快捷键
  10. linux内核奇遇记之md源代码解读之十一raid5d
  11. 如何获取音乐的地址链接
  12. 网络上各种指数 总结 收集
  13. linux卸载软件wine,Ubuntu 卸载wine
  14. 新型发明创造大赛计算机类,参加2019自主招生要具备什么条件?高校更青睐包括专利在内的七大类!...
  15. html带有进度条的登陆,带进度条上传
  16. Unity 自定义Package
  17. Unity C# compiler: CS0121: The call is ambiguous between the following methods or properties
  18. 硬盘驱动安装完成,但是没有显示?
  19. 最常见6大防采集套路及解决方法,建议收藏!
  20. 用计算机怎么弹学猫叫,抖音我们一起学猫叫计算器谱分享

热门文章

  1. React中构造函数、reader和函数的调用次数和时机测试
  2. volatile可以保证原子性吗
  3. IP暴露接口IP白名单设置
  4. java集合—— 链表(java中的所有链表都是双向链表)
  5. leetcode初级算法4.只出现一次的数字
  6. MySQL 对于千万级的大表要怎么优化?
  7. 托管 非托管_如何在托管的Kubernetes上备份Neo4J
  8. php cdi_Quarkus的其他(非标准)CDI功能
  9. java模板方法模式_Java中的模板方法模式
  10. apache ignite_使用Apache Storm和Apache Ignite进行复杂事件处理(CEP)