Java 抽象工厂模式

接上篇: Java 工厂方法模式

抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
抽象工厂允许客户使用抽象的接口来创建一组相关的产品(工厂方法模式只创建一个产品),而不需要知道(或者关心)实际产出的具体产品是什么。这样一来,客户就从具体的产品中被解耦。

这里写图片描述

完全不知道上面两段在说什么…,还是去卖披萨吧。

先交代一下做披萨的原料:腊肉,番茄酱,芝士等等(完全是我随便说的,从小到大我就吃过一次披萨,还是别人买的,尝了一小块)。

开始披萨加盟店都干得很好,赚了不少dollars,但是人心不足蛇吞象啊,随着时间的推移,有的加盟店发现可以在某些地方降低成本来获取更大的利润。某些黑心的加盟店主(由其是在中国的某些加盟店,前段时间还听说KFC使用的鸡肉都是变质的),发现做披萨的原料,并不需要完全是有机、绿色、无公害的原料。也可以使用质量比较次的、各种有害添加剂的原料替代。披萨购买者轻易不会发现披萨的味道变化,可是时间久了,就会对披萨使用者身体产生伤害。但是作为一个目光敏锐,深谋远虑的良心企业家,你发现了这个问题。你知道,这样长久下去肯定会被曝光,而且企业也可能像三鹿奶粉一样瞬间崩塌,所以你决定改变这种不规范、违法的现象。

怎么改变呢?你想到了一个办法,你自己来建立原料工厂,所有制作披萨所需要的原料都来自这个工厂(你能保证来自你这个工厂的原料都是健康的)。然后你要考虑下面的问题。

  1. 这些原料都是制作披萨相关的(一个产品族),是在一个工厂里提供,还是每种原料都建一个工厂来提供?
  2. 你要在全世界各地建立原料分工厂,每个地方的工厂都是生产一样的产品(腊肉,番茄酱,芝士。但是生产出来的产品都带有区域特色)。

经过慎重考虑:你决定在一个工厂里提供所有制作披萨相关的原料,并提供一个抽象的工厂,全世界各地的工厂都继承这个抽象的工厂。(如果每种原料都建一个工厂,就成了工厂方法模式了)

下面上代码

建造原料工厂

开始先为工厂定义一个接口,这个接口负责提供所有的原料。

public abstract class AbstractIngredientFactory {

    //提供腊肉
    protected abstract Bacon createBacon();

    //提供番茄酱
    protected abstract Ketchup createKetchup();

    //提供芝士
    protected abstract Cheese createCheese();

}

下面要做的事情

  1. 实现一组原料类供工厂使用,例如甜味腊肉,咸味腊肉,沙拉番茄酱,大蒜番茄酱,奶酪芝士,蓝莓芝士。这些类可以在不同的区域之间共享。
  2. 为每一个区域建造一个工厂,这些工厂都继承AbstractIngredientFactory 并实现所有的提供原料的方法。
  3. 然后将一切组织起来,将新的原料工厂和旧的PizzaStore整合起来。

提供一组原料类

一组腊肉

/**
 * 腊肉
 */
public class Bacon {
}

/**
 * 甜味腊肉
 */
public class SweetyBacon extends Bacon {
}

/**
 * 咸味腊肉
 */
public class SaltyBacon extends Bacon {
}

一组番茄酱

/**
 * 番茄酱
 */
public class Ketchup {
}

/**
 * 大蒜番茄酱
 */
public class GarlicKetchup extends Ketchup {
}

/**
 * 沙拉番茄酱
 */
public class SaladKetchup extends Ketchup {
}

一组芝士就省略了。

不同区域的原料工厂

上海的获取原料工厂

public class SHIngredientFactory extends AbstractIngredientFactory {

   
    @Override
    protected Bacon createBacon() {
        //上海人喜欢吃咸味腊肉
        return new SaltyBacon();
    }

    @Override
    protected Ketchup createKetchup() {
        //上海人喜欢吃大蒜番茄酱
        return new GarlicKetchup();
    }

    @Override
    protected Cheese createCheese() {
        //上海人喜欢吃奶酪芝士
        return new ReggianoCheese();
    }
}

纽约的获取原料工厂

public class NYIngredientFactory extends AbstractIngredientFactory {

    @Override
    protected Bacon createBacon() {
        //纽约人喜欢吃甜味腊肉
        return new SweetyBacon();
    }

    @Override
    protected Ketchup createKetchup() {
        //纽约人喜欢吃沙拉番茄酱
        return new SaladKetchup();
    }

    @Override
    protected Cheese createCheese() {
        //纽约人喜欢吃蓝莓芝士
        return new BlueberryCheese();
    }
}

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

public abstract class Pizza {

    //腊肉
    protected Bacon bacon;
    //番茄酱
    protected Ketchup ketchup;
    //大豆油
    protected Cheese cheese;

    //准备方法声明称抽象的,在这个方法中,需要收集比萨所需的原料,而这些原料来自原料工厂
    abstract void prepare();

    void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }

    void cut() {
        System.out.println("Cutting the pizza into diagonal slices");
    }

    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    @Override
    public String toString() {
        return "[bacon:" + bacon + ",ketchup:" + ketchup + ",cheese:" + cheese + "]";
    }

}

Pizza的代码使用相关的工厂提供的原料。原料依赖于特定的工厂。Pizza类根本不关心这些原料,它只知道如何制作披萨。

/**
 * 腊肉披萨
 */
public class BaconPizza extends Pizza {

    AbstractIngredientFactory factory;

    /**
     * 要制作披萨,需要从工厂里获取优质原料,所以需要传入一个原料工厂实例
     *
     * @param factory 原料工厂
     */
    public BaconPizza(AbstractIngredientFactory factory) {
        this.factory = factory;
    }

    @Override
    void prepare() {
        System.out.println("Preparing" + name);
        //prepare方法从原料工厂获取原料,腊肉披萨需要芝士和腊肉
        cheese = factory.createCheese();
        bacon = factory.createBacon();
    }
}

/**
 * 番茄酱披萨
 */
public class KetchupPizza extends Pizza {

    AbstractIngredientFactory factory;

    /**
     * 要制作披萨,需要从工厂里获取优质原料,所以需要传入一个原料工厂实例
     *
     * @param factory 原料工厂
     */
    public KetchupPizza(AbstractIngredientFactory factory) {
        this.factory = factory;
    }

    @Override
    void prepare() {
        System.out.println("Preparing" + name);
        //prepare方法从原料工厂获取原料,番茄酱披萨需要芝士和番茄酱
        cheese = factory.createCheese();
        ketchup = factory.createKetchup();
    }
}

现在看看披萨店的变化

上海的披萨店

public class SHPizzaStore extends PizzaStore {

    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        //上海的披萨店,制造披萨的时候,使用的是上海的原料工厂
        AbstractIngredientFactory factory = new SHIngredientFactory();
        if (type.equals("bacon")) {
            //制造出来的是上海风味的腊肉披萨
            pizza = new BaconPizza(factory);
        } else if (type.equals("ketchup")) {
            //制造出来的是上海风味的番茄酱披萨
            pizza = new KetchupPizza(factory);
        }
        return pizza;
    }
}

纽约披萨店

public class NYPizzaStore extends PizzaStore {

    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        //传入的是纽约的原料工厂
        AbstractIngredientFactory factory = new NYIngredientFactory();
        if (type.equals("bacon")) {
            //制造出来的是纽约风味的腊肉披萨
            pizza = new BaconPizza(factory);
        } else if (type.equals("ketchup")) {
            //制造出来的是纽约风味的番茄酱披萨
            pizza = new KetchupPizza(factory);
        }
        return pizza;
    }
}

现在就可以愉快的的点披萨了。

public class Client {

    public static void main(String[] args) {
        //在上海吃上海风味的披萨
        PizzaStore shStore = new SHPizzaStore();
        Pizza shCheesePizza = shStore.orderPizza("cheese");

        //在纽约吃纽约风味的披萨
        PizzaStore nyStore = new NYPizzaStore();
        Pizza nyCheesePizza = nyStore.orderPizza("cheese");
    }
}

抽象工厂模式做了什么?

  1. 定义抽象工厂,来提供披萨的原料家族。
  2. 我们的披萨店可以替换不同的工厂生产出不同的产品。(上海披萨店可以使用纽约的原料工厂来生产纽约风味的披萨)

再来回顾一下抽象工厂模式

抽象工厂允许客户(在这里是披萨店)使用抽象的接口(AbstractIngredientFactory)来创建一组相关的产品(制作披萨所用的原料),而不需要知道(或者关心)实际产出的具体产品是什么(我们只要知道工厂提供的原料是绿色健康的就行)。这样一来,客户就从具体的产品中被解耦。

抽象工厂模式的优缺点

优点

具体类的创建实例过程与客户端分离,客户端通过工厂的抽象接口操纵实例,客户端并不知道具体的实现是谁。

缺点

如果产品族中需要增加新的产品,则也需要修改抽象工厂和所有的具体工厂。

抽象工厂模式的使用场景

一个系统不依赖于产品线实例如何被创建、组合和表达的细节。系统中有多于一个的产品线,而每次只使用其中某一产品线。一个产品线(或是一组没有任何关系的对象)拥有相同的约束。

先记下来,以后再慢慢理解。。。

参考链接:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值