设计模式之工厂模式(四)

上篇我们从理论上了解了什么是工厂方法模式,也知道了创建者类和产品类的主要作用是什么。更重要的是,我们还学到了一个设计原则依赖倒置原则,这个原则能推导出我们为什么会使用工厂模式。

当然啦,上次还留下几个指导方针帮助我们去遵循依赖倒置原则。所以,接下来,我们就利用这几个方针,跟着方法,来重新设计下我们的披萨店。

原料工厂

我们知道,每一家加盟店的产生都是要经过层层筛选的,尤其是这种食品店。要确保每家加盟店使用的是高质量的原材料,那么如何确保每家加盟店使用高质量的原料?我们打算造一家生产原料的工厂,并将原料运送到各个地方。

但是,这个做法还存在一个问题。就比如我们周围的沙县小吃,每个沙县小吃的套餐饭的配料是不同的。这里同样,比如纽约和芝加哥,使用的酱料是不一样的。那么,我们就需要准备两组不同的原料来。将来多了几个加盟店,那么原料也是需要多一组的。

建造原料工厂

所以,我们要建造一个工厂来生产原料;这个工厂将负责创建原料家族中的每一种原料。也就是说,这个工厂,将需要根据地域不同,生产不同的原料。晚点,你就知道如何处理各个区域的差异了。

首先,先为工厂定义一个接口,这个接口负责创建所有的原料:

public interface PizzaIngredientFactory {

public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();

}

根据代码,我们知道,我们要做的事情是:

  1. 为每个区域建造一个工厂。你需要创建一个继承自PizzaIngredientFactory的子类来实现每一个创建方法
  2. 实现一组原料类供工厂使用,例如ReegianoCheese、RedPeppers、ThickCrustDough。这些类可以在合适的区域间共享
  3. 然后你忍让需要将这一切组织起来,将新的原料工厂整合进旧的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;
}

我们做了什么?

那么,通过一系列的代码改变,我们到底做了什么呢?在此,小编提供书上的结论来给大家,防止小编说的不够明确。

我们再来梳理下下订单的流程:
一开始订购的流程依然不变

  1. 首先,我们需要一个纽约的披萨店
// 创建一个实例
PizzaStore nyPizzaStore = new NYPizzaStore();
  1. 现在已经有一个披萨店了,可以接受订单:
// 调用nyPizzaStore实例的orderPizza()方法
nyPizzaStore.orderPizza("cheese");
  1. orderPizza()方法首先调用createPizza()方法
Pizza pizza = createPizza("cheese");

接下来,我们就用到了原料工厂,和之前的步骤不太一样了
4. 当createPizza()方法被调用时,也就开始涉及原料工厂了

// 选择原料工厂,接着在PizzaStore中实例化,然后将它传进每个披萨的构造器中
Pizza pizza = new CheesePizza(nyIngredientFactory);
  1. 接下来需要准备披萨。一旦调用了prepare()方法,工厂将被要求准备原料
public void prepare() {
    dough = factory.createDough();
    sauce = factory.createSauce();
    cheese = factory.createCheese();
}
  1. 最后,我们得到了准备好的披萨,orderPizza()就会接着烘烤、切片、盒装

到这里为止,我们已经把这个披萨店改造完成了,通过了工厂模式的另一个重要的模式抽象工厂模式。他提供一个接口, 用于创建相关或依赖对象的家族,而不需要明确指定具体类。

对于抽象工厂模式,已经工厂方法模式的对于等,还需要点时间整理,我将在下次推文中进行总结。

这次学习,主要是根据上次留下的设计原则,以此为线索来对我们之前的披萨加盟店进行优化改造,才有了这次的成功。披萨已经吃完了,你吃饱了吗?

爱生活,爱学习,爱感悟,爱挨踢

(0)

相关推荐

  • 设计模式之工厂模式(三)

    上一次我们已经通过代码,简单的认识了工厂方法模式,具体的思路请移步到设计模式之工厂模式(二),进行查看.这次,让我们通过设计模式的思想,来好好认识下工厂方法模式. 创建者和产品 所有工厂模式都用来封装 ...

  • 口语 | "pizza face" 不是 ”披萨脸”!

    对话框回复"早安"和"晚安",获取暖心音频问候 - 主播 | Scott - 1 pizza face 披萨脸 × 长很多痘痘的脸 √ 这个嘛,你想一想pizz ...

  • java设计模式2————工厂模式

    java设计模式2————工厂模式

  • 漫谈golang设计模式 简易工厂模式

    目前学习golang的主要需求是为了看懂TiDB的源码,下面我们复习一下简易工厂模式的思想 工厂类型分为三种,创建型模式,结构型模式,行为型模式. 简单工厂 使用场景:考虑一个简单的API设计,一个模 ...

  • 设计模式之工厂模式(下篇)

    今天我们来讲一讲抽象工厂: 重要涉及原则:要依赖抽象,不要依赖具体. 首先我们需要了解一个设计原则--依赖倒置原则:减少对具体的依赖,所谓的倒置是倒置的                         ...

  • 设计模式:工厂模式,解除耦合的利器

    工厂模式是使用频率很高的一种设计模式,在面试中也经常问到,今天我们就来学习它. 为什么要用工厂模式? 解答这个问题前,我们先来了解什么是工厂模式. 工厂模式其实也称创建模式,是用于创建对象的一种方式. ...

  • 设计模式之工厂模式(factory pattern)

    工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式.该模式用于封装和管理对象的创建,是一种创建型模式.本文从一 ...

  • 设计模式——抽象工厂模式

    抽象工厂方法_将关联组件组装成产品 ** * 印刷抽象工厂类 * @author maikec * 2019/5/20 */ public abstract class AbstractPrintin ...

  • 设计模式-工厂模式

    工厂模式 当我们创建一个对象比较复杂时且客户端不关心于实例对象的创建过程时我们可以用工厂模式 类型: 简单工厂模式 工厂方法模式 抽象工厂模式 简单工厂模式 百度百科 简单工厂模式是属于创建型模式,又 ...

  • 【设计模式】(四)抽象工厂模式(Abstract Factory Pattern)

    【设计模式】(四)抽象工厂模式(Abstract Factory Pattern)