《Head first设计模式》之抽象工厂

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

确保原料的一致

披萨店成功的关键在于新鲜、高质量的原料。要如何确保每家加盟店使用高质量的原料?你打算建造一家生成原料的工厂,并将原料运送到各家加盟店。对于这个做法,现在还剩下一个问题:加盟店坐落在不同的区域,纽约的红酱料和芝加哥的红酱料是不一样的。加盟店之间有相同的产品家族(意式腊肠、酱料、芝士、蔬菜等等),但是制作方式根据区域的不同而有差异。所以对于纽约和芝加哥,你准备了两组不同的原料。假如不久之后加州就有加盟店了,到时候是不是又需要一组新的原料?

建造原料工厂

现在,我们要建造一个工厂来生产原料,这个工厂将负责创建原料家族中的每一种原料。也就是说,工厂将需要生产面团、酱料、芝士等。
开始先为工厂定义一个接口,这个接口负责创建所有的原料:

public interface PizzaIngredientFactory {
    // 在接口中,每个原料都有一个对应的方法创建该原料
    public Dough createDough();
    public Sauce createSauce();
    public Cheese createCheese();
    public Veggies[] createVeggies();
    public Pepperoni createPepperoni();
    public Clams createClams();
}

现在要做的事情是:

  1. 为每个区域建造一个工厂。你需要创建一个继承自PizzaIngredientFactory的子类来实现每一个创建方法;
  2. 实现一组原料类供工厂使用,例如ReggianoCheese、RedPeppers、ThickCrustDough。这些类可以在合适的区域间共享;
  3. 然后你需要将一切组织起来,将新的原料工厂整合进旧的PizzaStore代码中。

创建纽约原料工厂

这是纽约原料工厂的实现。这工厂专精于大蒜番茄酱料、Reggiano干酪、新鲜蛤蜊。

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    // 对于原料家族内的每一种原料,我们都提供了纽约的版本
    @Override
    public Dough createDough() {
        return new ThinCrushDough();
    }

    @Override
    public Sauce createSauce() {
        return new MarinaraSauce();
    }

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }

    @Override
    public Veggies[] createVeggies() {
        Veggies veggies[] = {new Garlic(), new Onion(), new Mushroom(), new RedPepper()};
        return veggies;
    }

    @Override
    public Pepperoni createPepperoni() {
        // 这是切片的意式腊肠,纽约和芝加哥都会用到它
        return new SlicedPepperoni();
    }

    @Override
    public Clams createClams() {
        // 纽约靠海,所以有新鲜的蛤蜊。芝加哥就必须使用冷冻的蛤蜊
        return new FreshClams();
    }
}

重做披萨

工厂已经一切就绪,准备生成高质量原料了。现在我们只需要重做披萨,好让它们只使用工厂生产出来的原料。我们先从抽象的Pizza类开始:

public abstract class Pizza {
    String name;
    // 每个披萨都持有一组在准备时会用到的原料
    Dough dough;
    Sauce sauce;
    Veggies veggies[];
    Cheese cheese;
    Pepperoni pepperoni;
    Clams clams;

    // 现在把prepare()方法声明成抽象。在这个方法中,我们需要收集披萨所需的原料,而这些原料当然是来自原料工厂了。
    abstract void prepare();

    // 其他的方法保持不动
    void bake(){
        // ...
    }

    void cut(){
        // ...
    }

    void box(){
        // ...
    }
}

现在已经有了一个抽象披萨,可以开始创建纽约和芝加哥风味的披萨了。从今以后,加盟店必须直接从工厂取得原料。
我们曾经写过工厂方法的代码,有NYCheesePizza和ChicagoCheesePizza类。比较一下这两个类,唯一的差别在于使用区域性的原料,至于披萨的做法都一样。它们都依循着相同的准备步骤,只是使用不同的原料。
所以,其实我们不需要设计两个不同的类来处理不同风味的披萨,让原料工厂处理这种区域差异就可以了。下面是CheesePizza:

public class CheesePizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;

    // 要制作披萨,需要工厂提供原料。
    // 所以每个披萨类都需要从构造器参数中得到一个工厂,并把这个工厂存储在一个实例变量中。
    public CheesePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }

    @Override
    void prepare() {
        // prepare()方法一步一步地创建芝士披萨,每当需要原料时,就跟工厂要。
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
    }
}

Pizza的代码利用相关的工厂生成原料。所生产的原料依赖所使用的工厂,Pizza类根本不关心这些原料,它只知道如何制作披萨。现在,Pizza和区域原料之间被解耦,无论原料工厂是在落基山脉还是在西北沿岸地区,Pizza类都可以轻易地复用,完全没有问题。

再回到披萨店

我们几乎完工了,只需再到加盟店短暂巡视一下,确认他们使用了正确的披萨。也需要让他们能和本地的原料工厂搭上线:

public class NYPizzaStore extends PizzaStore {

    protected Pizza createPizza(String item) {
        Pizza pizza = null;
        // 纽约店会用到纽约披萨原料工厂,由该原料工厂负责生产使用纽约风味披萨所需的原料
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();

        if (item.equals("cheese")) {
            // 把工厂传递给每一个披萨,以便披萨能从工厂中取得原料
            pizza = new CheesePizza(ingredientFactory);
        } else if (item.equals("veggie")) {
            pizza = new VeggiePizza(ingredientFactory);
        } else if (item.equals("clam")) {
            pizza = new ClamPizza(ingredientFactory);
        } else if (item.equals("pepperoni")) {
            pizza = new PepperoniPizza(ingredientFactory);
        }
        return pizza;
    }
}

我们做了些什么?

一连串的代码改变,我们到底做了些什么?
我们引入新类型的工厂,也就是所谓的抽象工厂,来创建披萨原料家族。
通过抽象工厂所提供的接口,可以创建产品的家族,利用这个接口书写代码,我们的代码将从实际工厂解耦,以便在不同环境中实现各式各样的工厂,制造出各种不同的产品。例如:不同的区域、不同的操作系统、不同的外观及操作。
因为代码从实际的产品中解耦了,所以我们可以替换不同的工厂来取得不同的行为,例如取得大蒜番茄酱料,而不是取得番茄酱料。

比较工厂方法和抽象工厂

PizzaStore实现为工厂方法,因为我们需要根据区域变化创建产品。通过工厂方法,每个区域都有自己的具体工厂,他们都知道如何制作适合该区域的披萨。

因为我们需要创建一个产品家族(也就是原料),我们把PizzaIngredientFactory实现为抽象工厂。每个子类都使用其区域的供货商来实现这些原料。

工厂方法使用继承,把对象的创建委托给子类,子类实现工厂方法来创建对象。工厂方法允许类将实例化延迟到子类进行。

抽象工厂使用对象组合,对象的创建被实现在工厂接口所暴露出来的方法中。抽象工厂创建相关的对象家族,而不需要依赖它们的具体类。

所有工厂都是用来封装对象的创建。所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合。

原文地址:https://www.cnblogs.com/dafengdeai/p/12199104.html

时间: 2024-11-02 02:11:59

《Head first设计模式》之抽象工厂的相关文章

设计模式之抽象工厂模式

抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 最大的好处便是易于交换产品系列,由于具体工厂类,在一个应用中只需在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需改变具体工厂即可使用不同的产品配置. 他使具体创建实例的过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离. 下面的代码还使用了反射与XML. 代码如下: using System; using System.Collections.Ge

设计模式之抽象工厂模式20170803

创建型设计模式之抽象工厂模式: 一.含义 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类. 具体来说, 为一组具有相同约束(属性)的对象,提供一个接口,这个接口下有不同的实现,每个实现类对应一种类型的约束(一种具体的属性),同时提供该类型的约束(属性)下所有对象的创建方法 二.代码说明 1.主要有两个角色 1)一组互相影响的产品线(对象),也叫做产品族 2)抽象工厂类及其实现类 抽象工厂类:在N个产品族中,在抽象工厂类中就应该有N个创建方法 实现类:具体实现类是产品族的具体

设计模式 之 抽象工厂

    工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销.此时,我们可以考虑将一些相关的产品组成一个"产品族",由同一个工厂来统一生产,这就是我们本文将要学习的抽象工厂模式的基本思想. Abstract Factory(抽象工厂模式):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 在多年以后的某一天,当你陪着你的爱人去逛电器商场为家里添

大话设计模式_抽象工厂模式(Java代码)

抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类. 简单描述:有多种抽象产品,并且每种抽象产品都有多个具体产品.一个抽象工厂,提供多个具体工厂,每个工厂则提供不同种类的具体产品. 大话设计模式中的截图: 例子代码: AbstractProductA类: 1 package com.longsheng.abstractfactory; 2 3 public abstract class AbstractProductA { 4 5 public abstract v

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

设计模式三-抽象工厂模式 一.定义 抽象工厂模式是工厂方法模式的进一步抽象.如果产品簇中只有一种产品,则退化为工厂方法模式. 二.原理图 三.代码实例 * 苹果和土豆是园丁1的杰作 * 葡萄和西红柿是园丁2的杰作 1.Fruit.java public interface Fruit { /* * 生长 * 收获 * 栽种 */ public void grow(); public void harvest(); public void plant(); } 2.Apple.java publi

跟我学设计模式视频教程——抽象工厂,建造者

课程视频 抽象工厂 建造者 唠嗑 课程笔记 课程笔记 课程代码 课程代码 新课程火热报名中 课程介绍 跟我学设计模式视频教程--抽象工厂,建造者

Java设计模式之抽象工厂(02)

对工厂方法进行抽象.当增加新的产品时,不用改动工厂类.而是集成已有的工厂接口或者抽象工厂,创建新的工厂.这就是对扩展开发,对修改封闭. 1 package Pak; 2 3 public abstract class Automobile { 4 public abstract void Run(); 5 } package Pak; public class Bus extends Automobile { @Override public void Run() { System.out.pr

设计模式之抽象工厂模式(Abstract Factory)

1.定义 抽象工厂模式为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 2.类图 由于类太多就不上源码了~ 最佳实践: 在一个应用中,需要在三个不同平台(Windows.Linux.Android)上运行,通过抽象工厂模式屏蔽掉操作系统对应的影响三个不同操作系统上的软件功能.应用逻辑.UI都应该是非常类似的,唯一不同的是调用不同的工厂方法,由不同的产品类去处理与操作系统交互的信息. 设计模式之抽象工厂模式(Abstract Factory)

C#设计模式之三抽象工厂模式(AbstractFactory)【创建型】

原文:C#设计模式之三抽象工厂模式(AbstractFactory)[创建型] 一.引言 写了3篇有关设计模式的文章了,大家有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力.今天我要写第四个模式了,该模式叫抽象工厂.上一篇文章我们讲了[工厂方法]模式,它是为了解决[简单工厂]模式所面对的问题,它的问题就是:如果我们增加新的产品,工厂类的方法就要修改本身的代码,增加产品越多,其逻辑越复杂,同时这样的修改也是不符合[开放关闭原则OCP],对修改代码关闭,对增加代码开放.为了解决[简单工厂

iOS 设计模式之抽象工厂

设计模式是程序提升的必备知识,这里说下iOS如何实现抽象工厂设计模式.本文是看过oc编程之道这本的抽象工厂这章后写出的,如果不明白原理可以看看那本书. TestView.h首先创建一个视图 // // TestView.h // AbstractFactory // // Created by 杜甲 on 11/10/14. // Copyright (c) 2014 杜甲. All rights reserved. // #import <UIKit/UIKit.h> @interface