抽象工厂模式定义
工厂方法模式中工厂只负责同类产品的生产。比如电视机工厂不应该生产汽车。
然而现实生活中有很多综合型的工厂,比如有些电视工厂不仅生产电视机,还会生产与之配套的机顶盒。
那么抽象工厂模式随之诞生,这种模式将考虑多种类型产品的生产。
我们总结下:
“”
- 工厂方法模式只考虑成产同一等级级的产品
- 抽象方法模式考虑生产多等级的产品,可以说是工厂方法模式的升级版
如上图,小米音响和苹果音响为同一个产品。而小米手机和小米音响为同一产品族。
使用场景
那么什么情况下可以使用抽象工厂模式?
使用抽象工厂模式一般要满足以下条件。
- 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
- 系统一次只可能消费其中某一族产品,即同族的产品一起使用。
抽象工厂模式同工厂方法模式结构一样,需要抽象产品,抽象工厂,具体产品,具体工厂4部分组成。
结构图如下:
实现代码
这个图你可能看着头晕,我们用代码来表示:
首先创建抽象工厂AbstractFactory
public interface AbstractFactory {
Product1 newProduct1();
Product2 newProduct2();
}
然后在创建两个抽象产品
/**
* 手机
*/
public interface Product1 {
void show();
}
/**
* 音响
*/
public interface Product2 {
void show();
}
然后创建具体产品
public class ConcreteProduct11 implements Product1 {
@Override
public void show() {
System.out.println("具体产品11显示【小米-手机】...");
}
}
public class ConcreteProduct12 implements Product1 {
@Override
public void show() {
System.out.println("具体产品12显示【苹果-手机】...");
}
}
public class ConcreteProduct21 implements Product2 {
@Override
public void show() {
System.out.println("具体产品21显示【小米-音响】...");
}
}
public class ConcreteProduct22 implements Product2 {
@Override
public void show() {
System.out.println("具体产品22显示【苹果-音响】...");
}
}
再创建具体工厂ConcreteFactory1
用来生产小米产品【小米-手机,小米-音响】
/**
* Description: 小米工厂
*
* @author Lvshen
* @since JDK 1.8
*/
public class ConcreteFactory1 implements AbstractFactory {
public Product1 newProduct1() {
System.out.println("具体工厂 1 【小米工厂】 生成-->具体产品 11...");
return new ConcreteProduct11();
}
public Product2 newProduct2() {
System.out.println("具体工厂 1 【小米工厂】 生成-->具体产品 21...");
return new ConcreteProduct21();
}
}
ConcreteFactory1
用来生产苹果产品【苹果-手机,苹果-音响】
/**
* Description: 苹果工厂
*
* @author Lvshen
* @since JDK 1.8
*/
public class ConcreteFactory2 implements AbstractFactory {
public Product1 newProduct1()
{
System.out.println("具体工厂 2 【苹果工厂】生成-->具体产品 12...");
return new ConcreteProduct12();
}
public Product2 newProduct2()
{
System.out.println("具体工厂 2 【苹果工厂】生成-->具体产品 22...");
return new ConcreteProduct22();
}
}
测试
我们使用小米工厂,生产小米手机
@Slf4j
public class FactoryTest {
@Test
public void test() {
ConcreteFactory1 concreteFactory1 = new ConcreteFactory1();
Product1 product1 = concreteFactory1.newProduct1();
product1.show();
}
}
测试结果
我们再来用苹果工厂生产苹果音响
@Slf4j
public class FactoryTest {
@Test
public void test() {
ConcreteFactory2 concreteFactory = new ConcreteFactory2();
Product2 product = concreteFactory.newProduct2();
product.show();
}
}
测试结果
关于抽象工厂模式的思考
当新增一条产品族时,只需要新增一个工厂即可。比如新增华为手机,华为音响,我们就需要需新增华为工厂。
如果新增新产品等级的产品,那么就需要修改工厂。假如我们新增了手环产品,比如小米手环,苹果手环,华为手环。那么,每个工厂都需要修改。这并不满足闭开原则。
我们再总结下什么情况下会使用抽象工厂模式:
“”
- 系统中有多个产品族,但每次只使用其中的某一族产品。比如我就喜欢专门使用小米的手机和手环
- 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构
同工厂模式一样,抽象工厂模式的优点在于,我们不需要知道产品是如何创建的。要获取产品对象,通过工厂就可以获取。做到了很好的封装。
如果产品族类的产品与产品之间存在约束,比如小米手环和小米手机有一定的约束【小米手环需要与小米手机配对才能激活小米手环(这里我瞎说,只是举个栗子)】。那么可以在小米工厂内做出约束,用户并不需要知道内部如如何约束。
我们再来列举一个使用场景
“如一个文本编辑器和一个图片处理器,都是软件实体,但是Linux下的文本编辑器和Windows下的文本编辑器虽然功能和界面都相同,但是代码实现是不同的,图片处理器也有类似情况。也就是具有了共同的约束条件:操作系统类型。于是我们可以使用抽象工厂模式,产生不同操作系统下的编辑器和图片处理器。