《Head-First-设计模式》笔记6-抽象工厂模式

定义

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象

需求

现在不同的比萨连锁店需要各自配备自己独特的一组原料。

现在要做的就是:

  1. 为每个区域创建一个工厂,工厂可以生产一组该区域需要的原料。
  2. 实现一组原料类供工厂使用。
  3. 将新的工厂整合进原来的 PizzaStore 类。

代码实现

定义一个原料工厂接口

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

创建原料工厂

public class NYPizzaIngredientFactory implements PizzaIngredientFactory{

    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }

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

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

重做披萨

public abstract class Pizza {
    /*每个披萨都持有一组在准备时会用到的原料 */
    String name;
    Dough dough;
    Sauce sauce;
    Cheese cheese;

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

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void bake(){
        System.out.println("Bake for 25 minutes at 350");
    }
    public void cut() {
        System.out.println("Cutting the pizza into diagonal slices");
    }
    public void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }
    public String toString(){
        return "";
    }
}

披萨子类

public class CheesePizza extends Pizza {
    PizzaIngredientFactory factory;

    public CheesePizza(PizzaIngredientFactory factory) {
        this.factory = factory;
    }

    @Override
    void prepare() {
        System.out.println("Preparing " + name);
        dough = factory.createDough();
        sauce = factory.createSauce();
        cheese = factory.createCheese();
    }
}

披萨店子类

public class NYPizzaStore extends PizzaStore {
    @Override
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        PizzaIngredientFactory factory = new NYPizzaIngredientFactory();
        if (type.equals("cheese")) {
            pizza = new CheesePizza(factory);
            pizza.setName("NY Style Cheese Pizza");
        }
        return pizza;
    }
}

模式结构

抽象工厂模式包含如下角色:

AbstractFactory:抽象工厂
ConcreteFactory:具体工厂
AbstractProduct:抽象产品
Product:具体产品

工厂方法和抽象工厂区别

工厂方法的最大特点在于工厂接口只有一个工厂方法,具体产品的创建延迟到子类实现,客户端只需要知道获取了一个工厂对象,具体产品并不知道,实现客户端和具体产品的解耦。

而抽象工厂可以看做是工厂方法的升级版本,因为工厂方法可以看做生产一个产品等级的,抽象工厂则是生产不同产品等级的相关联的系列产品。但是正因为此,抽象工厂的缺点在于当向系列产品添加新的产品要修改抽象工厂的方法,这违背开放 -- 关闭原则的,而工厂方法若是添加新的产品只要扩展新的工厂类就可以了。

当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。

优缺点

优点

  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”(结合缺点看)。

缺点

  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
  • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

“开闭原则”的倾斜性

“开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:

  • 增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
  • 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。

抽象工厂模式的这种性质称为“开闭原则”的倾斜性,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供这样的方便。



转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com

文章标题:《Head-First-设计模式》笔记6-抽象工厂模式

文章字数:1.6k

本文作者:Bin

发布时间:2018-07-08, 22:31:27

最后更新:2019-08-06, 00:07:35

原始链接:http://coolview.github.io/2018/07/08/Head-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E3%80%8AHead-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%8B%E7%AC%94%E8%AE%B06-%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录