设计模式-抽象工厂模式

发布于 2021-01-15 22:26

抽象工厂模式

介绍: 提供一个创建一系列相关的相互依赖对象的接口,而无需指定它们具体的类。它和工厂方法模式的区别就在于所创建对象的复杂度上。抽象工厂和简单工厂、工厂方法相比是最具一般性的。

场景: 接着我们的pizza工厂,不过现在上头又增加了需求。他希望我们在中国pizza下面有番茄酱和沙拉酱两种口味,而美国pizza下面也有有番茄酱和沙拉酱两种口味。如果使用的是工厂方法模式,那么我们就需要再添加4种工厂分布制作不同的产品。

概念:

  1. 产品树:中国番茄酱pizza和中国沙拉酱pizza处于同一等级结构(产品树),US番茄酱pizza和US沙拉酱pizza也处于同一等级结构(产品树)
  2. 产品族:位于不同产品等级结构中功能相关联的产品组成的家族。中国番茄酱pizza与US番茄酱pizza属于同一产品族,中国沙拉酱pizza与US沙拉酱pizza属于同一产品族

优点: 工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。

一、抽象工厂

介绍: 我们将所有工厂的业务抽象出来,每个工厂必须实现对所有等级类别的产品的生产。每个子工厂用于实现一个产品族的生产。

  • 披萨定义部分pizza代码,请参照上篇文章—工厂方法模式

    // 中国番茄酱pizza
    public class KetchupChinesePizza extends ChinesePizza {

        @Override
        public void addSeasoning() {
            System.out.println("添加番茄酱");
        }

    }

    // 美国番茄酱pizza
    public class KetchupUSPizza extends USPizza {

        @Override
        public void addSeasoning() {
            System.out.println("添加番茄酱");
        }

    }

    // 中国沙拉酱pizza
    public class SaladChinesePizza extends ChinesePizza {

        @Override
        public void addSeasoning() {
            System.out.println("添加沙拉酱");
        }

    }

    // 美国沙拉酱pizza
    public class SaladUSPizza extends USPizza {

        @Override
        public void addSeasoning() {
            System.out.println("添加沙拉酱");
        }

    }
  • 抽象工厂能制作所有国家的番茄酱pizza

    public class KetchupPizzaFactory extends PizzaFactory {

        @Override
        public ChinesePizza createChinesePizza() {
            System.out.println("开始制作中国pizza");
            KetchupChinesePizza pizza = new KetchupChinesePizza();
            pizza.addFlour();
            pizza.addWater();
            pizza.addSeasoning();
            return pizza;
        }

        @Override
        public USPizza createUSPizza() {
            System.out.println("开始制作美国pizza");
            KetchupUSPizza pizza = new KetchupUSPizza();
            pizza.addFlour();
            pizza.addWater();
            pizza.addSeasoning();
            return pizza;
        }

    }
  • 沙拉酱工厂能制作所有国家的沙拉酱pizza

    public class SaladPizzaFactory extends PizzaFactory {

        @Override
        public ChinesePizza createChinesePizza() {
            System.out.println("开始制作中国pizza");
            SaladChinesePizza pizza = new SaladChinesePizza();
            pizza.addFlour();
            pizza.addWater();
            pizza.addSeasoning();
            return pizza;
        }

        @Override
        public USPizza createUSPizza() {
            System.out.println("开始制作美国pizza");
            SaladUSPizza pizza = new SaladUSPizza();
            pizza.addFlour();
            pizza.addWater();
            pizza.addSeasoning();
            return pizza;
        }

    }
  • 提供pizza业务

    public class TestMain {
        public static void main(String[] args) {
            PizzaFactory kf = new KetchupPizzaFactory();
            ChinesePizza pizza1 = kf.createChinesePizza();

            PizzaFactory sf = new SaladPizzaFactory();
            USPizza pizza2 = sf.createUSPizza();
        }
    }

    输出如下:

    开始制作中国pizza
    400克面粉
    100ml水
    添加番茄酱
    开始制作美国pizza
    300克面粉
    100ml水
    添加沙拉酱

不足: 如果我们再增加一个产品树(等级结构),比如巴西pizza,那么,我们需要为每个子工厂添加一个巴西披萨的制作方法。

二、静态抽象工厂

场景: 为了对上面的不足加以调整,我们可以通过静态工厂结合抽象工厂,并通过反射机制来对pizza进行制作。

  • 工厂类

    public class SRFactory {

        public static ChinesePizza createChinesePizza(String name) throws Exception {
            System.out.println("开始制作中国pizza");
            ChinesePizza pizza = (ChinesePizza) Class.forName(name).newInstance();
            pizza.addFlour();
            pizza.addWater();
            pizza.addSeasoning();
            return pizza;
        }

        public static USPizza createUSPizza(String name) throws Exception {
            System.out.println("开始制作美国pizza");
            USPizza pizza = (USPizza) Class.forName(name).newInstance();
            pizza.addFlour();
            pizza.addWater();
            pizza.addSeasoning();
            return pizza;
        }

    }
  • 提供pizza业务

    public static void main(String[] args) throws Exception {
        USPizza pizza = SRFactory.createUSPizza("com.devil.designmodel.factory.model.KetchupUSPizza");
        ChinesePizza pizza2 = SRFactory.createChinesePizza("com.devil.designmodel.factory.model.SaladChinesePizza");
    }

    输出如下:

    开始制作美国pizza
    加300克面粉
    加100ml水
    添加番茄酱
    开始制作中国pizza
    加400克面粉
    加100ml水
    添加沙拉酱

总结: 工厂模式在具体实践中是使用比较频繁的,但是我们需要了解他们的长处和不足,根据特定情况来决定需要使用的模式。

  1. 对于业务不会进行太多变更的,我们可以使用简单工厂
  2. 对于只考虑产品树形式的(产品不会再细分子类),可以考虑工厂方法
    对于多个产品等级结构的,我们应该选择合适的抽象工厂


往期回顾:

设计模式-分类与6大原则


本文来自网络或网友投稿,如有侵犯您的权益,请发邮件至:aisoutu@outlook.com 我们将第一时间删除。

相关素材