# 抽象工厂模式

# 场景

1、由于小安种的果树越来越多,来他这买水果的人也越来越多,但有的人希望直接来打包好的水果。因为要拿去送礼,这个时候产品就分为了 2 个系列:一个是水果系列,一个是包装盒系列。就相当于水果有自己的水果工厂,包装盒有包装盒工厂。

image-20210925141658266

2、但这样会出现特殊情况,就是本来是苹果包装盒,里面应该放苹果,结果打开却发现是橘子,这种情况就是由于水果工厂和包装盒工厂都在一起,包装过程中难免有疏漏。

image-20210925141944922

3、在经过上面的事情之后,小安就想了一个法子,让苹果和苹果包装盒呆在一起,桔子和桔子包装盒呆在一起,这样应该就不会出错了,于是就有了下面的方式。当使用不同工厂时,返回对应这一族的产品系列。

image-20210925142239201

# 抽象工厂模式

# 定义

提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。即当一个类别的产品还有多个系列区分时,为了按系列生产商品,使用抽象工厂区分。

# 结构

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。

  • 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。

  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品,如水果,包装盒。

  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

image-20210925150050946

# 实现

抽象工厂(Abstract Factory)

/**
 * 抽象工厂接口
 */
public  interface AbstractFactory {
    /**
     * 获取水果
     */
    Fruit getFruit();

    /**
     * 包装水果
     */
    Bag getBag();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

具体工厂(Concrete Factory)

/**
 * 苹果工厂
 */
public class AppleFactory implements AbstractFactory {
    @Override
    public Fruit getFruit() {
        return new Apple();
    }

    @Override
    public Bag getBag() {
        return new AppleBag();
    }
}

/**
 * 桔子工厂
 */
public class OrangeFactory implements AbstractFactory {
    @Override
    public Fruit getFruit() {
        return new Orange();
    }

    @Override
    public Bag getBag() {
        return new OrangeBag();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

抽象产品(Product)

//水果
public interface Fruit {
	//水果
    public void fruit();
}

//包装盒
public interface Bag {
    //打包
    void pack();
}
1
2
3
4
5
6
7
8
9
10
11

具体产品(ConcreteProduct)

//苹果
public class Apple implements Fruit {
    @Override
    public void fruit() {
        System.out.println("我是苹果");
    }
}

//橘子
public class Orange implements Fruit {
    @Override
    public void fruit() {
        System.out.println("我是桔子");
    }
}

/**
 * 苹果包装
 */
public class AppleBag implements Bag {
    @Override
    public void pack() {
        System.out.println("使用苹果盒包装");
    }
}

/**
 * 桔子包装
 */
public class OrangeBag implements Bag {
    @Override
    public void pack() {
        System.out.print("--我使用桔子盒包装");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

测试

public static void main(String[] args) {
    //初始化苹果工厂
    AbstractFactory factory = new AppleFactory();
    //在苹果工厂中拿苹果
    Fruit apple = factory.getFruit();
    apple.getFruit();
    //在苹果工厂中拿苹果包装盒
    Bag bag = factory.getBag();
    //包装
    bag.pack();
}

输出:
我是苹果使用苹果盒包装
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 优缺点

优点

  • 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
  • 当增加一个新的产品族时不需要修改原代码,满足开闭原则。

缺点

  • 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改,比如给包装盒在添加一个印章。

# 使用场景

  • 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  • 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

# 总结

相对于工厂方法模式,可以发现抽象工厂可产出不同等级的产品,也就是不同系列的产品,比如可以产生出水果,也可以产生出带包装的水果,这就是 2 个系列,而工厂方法就只能产出一个系列,就是不带包装的水果。

因此抽象工厂模式的本质是选择产品簇(族)实现

当然,当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式。