设计模式之工厂模式(四)
上篇我们从理论上了解了什么是工厂方法模式,也知道了创建者类和产品类的主要作用是什么。更重要的是,我们还学到了一个设计原则依赖倒置原则,这个原则能推导出我们为什么会使用工厂模式。
当然啦,上次还留下几个指导方针帮助我们去遵循依赖倒置原则。所以,接下来,我们就利用这几个方针,跟着方法,来重新设计下我们的披萨店。
原料工厂
我们知道,每一家加盟店的产生都是要经过层层筛选的,尤其是这种食品店。要确保每家加盟店使用的是高质量的原材料,那么如何确保每家加盟店使用高质量的原料?我们打算造一家生产原料的工厂,并将原料运送到各个地方。
但是,这个做法还存在一个问题。就比如我们周围的沙县小吃,每个沙县小吃的套餐饭的配料是不同的。这里同样,比如纽约和芝加哥,使用的酱料是不一样的。那么,我们就需要准备两组不同的原料来。将来多了几个加盟店,那么原料也是需要多一组的。
建造原料工厂
所以,我们要建造一个工厂来生产原料;这个工厂将负责创建原料家族中的每一种原料。也就是说,这个工厂,将需要根据地域不同,生产不同的原料。晚点,你就知道如何处理各个区域的差异了。
首先,先为工厂定义一个接口,这个接口负责创建所有的原料:
public interface PizzaIngredientFactory {public Dough createDough();public Sauce createSauce();public Cheese createCheese();public Veggies[] createVeggies();public Pepperoni createPepperoni();public Clams createClam();}
复制代码
根据代码,我们知道,我们要做的事情是:
- 为每个区域建造一个工厂。你需要创建一个继承自PizzaIngredientFactory的子类来实现每一个创建方法
- 实现一组原料类供工厂使用,例如ReegianoCheese、RedPeppers、ThickCrustDough。这些类可以在合适的区域间共享
- 然后你忍让需要将这一切组织起来,将新的原料工厂整合进旧的PizzaStore代码中
接下来,我们就可以创建一个工厂,这里以纽约原料工厂为例,其他工厂同理即可。这工厂主要是大蒜番茄酱料、Reggiano干酪等
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {public Dough createDough() {return new ThinCrustDough();}public Sauce createSauce() {return new MarinaraSauce();}public Cheese createCheese() {return new ReggianoCheese();}public Veggies[] createVeggies() {Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };return veggies;}public Pepperoni createPepperoni() {return new SlicedPepperoni();}public Clams createClam() {return new FreshClams();}
}
复制代码
重做披萨
工厂的流水线已经搞定了,接下来就是准备高质量的原料;现在我们只需要重做披萨,好让他们只使用工厂生产出来的原料。首先,我们把Pizza类的prepare声明称抽象。为什么呢?因为在这个方法中,我们需要搜集披萨所需的原料,而这些原料来自原料工厂。
abstract void prepare();
复制代码
我们拥有了一个抽象披萨,就可以开始创建纽约和芝加哥风味的披萨了。之前我们的工厂方法写过NYCheesePizza和ChicagoCheesePizza类,他们就是使用不同的原料罢了。
所以,其实我们不需要设计两个不同的类来处理不同风味的披萨,让原料工厂来处理即可。
public class CheesePizza extends Pizza {PizzaIngredientFactory ingredientFactory;// 要制作披萨,需要工厂提供原料。所以每个披萨都需要从构造器参数中得到一个工厂,并把这个工厂存储在一个实例变量中public CheesePizza(PizzaIngredientFactory ingredientFactory) {this.ingredientFactory = ingredientFactory;}// 神奇的事情发生在这public void prepare() {System.out.println("Preparing " + name);dough = ingredientFactory.createDough();sauce = ingredientFactory.createSauce();cheese = ingredientFactory.createCheese();}
}
复制代码
请看『sauce = ingredientFactory.createSauce()』,Pizza类不关心原料怎么来的,只知道如何制作披萨,Pizza和区域被完全解耦了。ingredientFactory是原料工厂,createSauce()会返回所在区域使用的原料,不管是哪个区域。
再次回到披萨店
所以,我们重新回到披萨店巡视下,就可以确认他们是否使用了正确的披萨。只要让他们和本地的原料工厂搭上线即可:
protected Pizza createPizza(String item) {Pizza pizza = null;// 纽约店会用到纽约披萨原料工厂,由该原料工厂负责生产所有纽约风味披萨所需的原料PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();if (item.equals("cheese")) {// 把工厂传递给每一个披萨,以便披萨能从工厂中去的原料pizza = new CheesePizza(ingredientFactory);pizza.setName("New York Style Cheese Pizza");} else if (item.equals("veggie")) {pizza = new VeggiePizza(ingredientFactory);pizza.setName("New York Style Veggie Pizza");} else if (item.equals("clam")) {pizza = new ClamPizza(ingredientFactory);pizza.setName("New York Style Clam Pizza");} else if (item.equals("pepperoni")) {pizza = new PepperoniPizza(ingredientFactory);pizza.setName("New York Style Pepperoni Pizza");} return pizza;}
复制代码
我们做了什么?
那么,通过一系列的代码改变,我们到底做了什么呢?在此,小编提供书上的结论来给大家,防止小编说的不够明确。
我们再来梳理下下订单的流程: 一开始订购的流程依然不变
- 首先,我们需要一个纽约的披萨店
// 创建一个实例
PizzaStore nyPizzaStore = new NYPizzaStore();
复制代码
- 现在已经有一个披萨店了,可以接受订单:
// 调用nyPizzaStore实例的orderPizza()方法
nyPizzaStore.orderPizza("cheese");
复制代码
- orderPizza()方法首先调用createPizza()方法
Pizza pizza = createPizza("cheese");
复制代码
接下来,我们就用到了原料工厂,和之前的步骤不太一样了 4. 当createPizza()方法被调用时,也就开始涉及原料工厂了
// 选择原料工厂,接着在PizzaStore中实例化,然后将它传进每个披萨的构造器中
Pizza pizza = new CheesePizza(nyIngredientFactory);
复制代码
- 接下来需要准备披萨。一旦调用了prepare()方法,工厂将被要求准备原料
public void prepare() {dough = factory.createDough();sauce = factory.createSauce();cheese = factory.createCheese();
}
复制代码
- 最后,我们得到了准备好的披萨,orderPizza()就会接着烘烤、切片、盒装
到这里为止,我们已经把这个披萨店改造完成了,通过了工厂模式的另一个重要的模式抽象工厂模式。他提供一个接口, 用于创建相关或依赖对象的家族,而不需要明确指定具体类。
对于抽象工厂模式,已经工厂方法模式的对于等,还需要点时间整理,我将在下次推文中进行总结。
这次学习,主要是根据上次留下的设计原则,以此为线索来对我们之前的披萨加盟店进行优化改造,才有了这次的成功。披萨已经吃完了,你吃饱了吗?
爱生活,爱学习,爱感悟,爱挨踢
转载于:https://juejin.im/post/5cbfe9566fb9a032165e21b5
设计模式之工厂模式(四)相关推荐
- 三角形圆形创建与擦除java_设计模式---------------简单工厂模式
设计模式---------------简单工厂模式 一.题目(Question) 使用简单工厂模式设计一个可以创建不同几何形状(如圆形.方形和三角形等)的绘图工具,每个几何图形都要有绘制draw()和 ...
- C#设计模式——简单工厂模式
一.引言 这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理解的模式--简单工厂模式. 二.简单工厂 ...
- 系统架构技能之设计模式-抽象工厂模式
一.上篇回顾 上篇我们主要讲述了简单工厂模式和工厂模式.并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下: 简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建 ...
- JAVA设计模式之工厂模式(三种工厂模式)
1.工厂模式可以分为三类: 简单工厂模式(Simple Factory) 工厂方法模式(Factory Method) 抽象工厂模式(Abstract Factory) 简单工厂其实不是一个标准的的设 ...
- Java设计模式(工厂模式>抽象工厂模式和原型模式)
Java设计模式Ⅱ 1.工厂模式 1.1 简单工厂模式 1.2 工厂方法模式 2.抽象工厂模式 3.总结 4.原型模式 4.1 原型模式 4.2 浅拷贝 4.3 深拷贝 5.建造者模式 1.工厂模式 ...
- JavaScript设计模式--简单工厂模式例子---XHR工厂
JavaScript设计模式--简单工厂模式例子---XHR工厂 第一步,Ajax操作接口(目的是起一个接口检测作用) (1)引入接口文件 //定义一个静态方法来实现接口与实现类的直接检验 //静态方 ...
- 策略模式和工厂模式的区别_设计模式之工厂模式-工厂方法模式
设计模式之工厂模式-工厂方法模式 大家好,欢迎来到污污弹公司,今天司小司又接到了一个新活-披萨项目. 来源:凯哥Java(kaigejava) 需求: 披萨项目: 要方便披萨品种的扩展.要便于维护.要 ...
- Java 设计模式之工厂模式(二)
原文地址:Java 设计模式之工厂模式(二) 博客地址:http://www.extlight.com 一.背景 本篇内容是 Java 设计模式创建型模式的第二篇.上一篇主题为 <Java 设计 ...
- 设计模式之工厂模式(三)
上一次我们已经通过代码,简单的认识了工厂方法模式,具体的思路请移步到设计模式之工厂模式(二),进行查看.这次,让我们通过设计模式的思想,来好好认识下工厂方法模式. 创建者和产品 所有工厂模式都用来封装 ...
- php工厂模式和单例模式,php 设计模式之工厂模式、单例模式、注册树模式
php 设计模式之工厂模式.单例模式.注册树模式 在软件工程中,创建型设计模式承担着对象创建的职责,尝试创建适合程序上下文的对象,对象创建设计模式的产生是由于软件工程设计的问题,具体说是向设计中增加复 ...
最新文章
- [转]数据库建立索引的一般依据
- SAP PM 初级系列18 - 为维修工单分配Permit
- linux fedora安装、运行mybase7.3.5报错:error while loading shared libraries: libpng12.so.0
- 洛谷P1067 多项式输出
- SQLSERVER:sqlserver2008r2安装好后,自动提示功能不可以使用
- S5PV210 Uboot开发与移植02:Uboot配置与编译
- 【廖雪峰官方网站/Java教程】设计模式(二)
- 摘抄 ander图片上传
- 基于Matlab的极限学习机(ELM)实现
- ITIL学习笔记——核心流程之:IT服务财务管理
- 使用vue-pdf-signature实现pdf预览
- canon iPF 系列保养墨盒清零方法
- excel公式识别html,POI/Excel/HTML单元格公式问题
- Italvibras M3/4-S02振动电机M3/20-S02 3/100-S02 3/200-S02 MVSI 3/300-S02振动电机
- Excel根据身份证号自动识别性别
- 那些年用过的时间衰减函数
- python爬虫爬取豆瓣电影排行榜,并写进csv文件,可视化数据分析
- 服务器被入侵如何排查
- 计算机毕业设计node.js+vue+Element电商后台管理系统
- 用导函数的图像判断原函数的单调性