一、介绍
抽象工厂模式(Abstract Factory Pattern)属于创建型设计模式。用于解决比工厂方法设计模式更加复杂的问题。
复杂到哪里了呢?
我们将抽象工厂模式和工厂模式进行简单的比较,或许可以有更好的理解:
- 工厂方法设计模式中,指定工厂只能创建对应的单个产品,是一对一的关系。
- 抽象工厂模式中,不仅需要创建产品的工厂,还多了一个创建工厂的工厂(顶级工厂)。当顶级工厂创建一个工厂时,顶级工厂与工厂是一对一的关系(等同于工厂模式),被创建的工厂可以生产多个产品,因此顶级工厂与产品之间是一对多的关系。
二、基本组件
在我们使用抽象工厂设计模式时,一般需要以下组件:
- 抽象工厂
- 工厂实现
- 抽象产品
- 产品实现
一般来讲,从抽象工厂中获取的对象类型为抽象类型,其具体类型由具体的工厂实现决定。
三、演示案例
唉,到了结婚的年纪了,我们就以结婚为例吧。
1. 定义抽象工厂
结婚是一件十分麻烦的事情,需要准备非常非常多的事情,比如婚车、婚房、婚纱照等等。所以我们以结婚为工厂,以婚车婚房婚纱照为产品。先对结婚这件事情做一个规范的定义。
public interface MarriageFactory {
/**
* 产品 - 婚车
*/
Car getCar();
/**
* 产品 - 婚房
*/
House getHouse();
/**
* 产品 - 婚纱照
*/
Picture getPicture();
}
2. 定义抽象产品
婚车
public interface Car { /** * 坐婚车 */ void drive(); }
婚房
public interface House { /** * 买房 */ void buyHouse(); }
婚纱照
public interface Picture { /** * 照相 */ void takePicture(); }
3. 定义具体工厂
我们结婚一般都是要找一个婚庆公司,假设婚庆公司都提供结婚的一条龙服务,包括婚车、婚房、婚纱照等业务,现在我们城里有两家婚庆公司:汤姆婚庆(TomFactory
) 和 杰瑞婚庆(JerryFactory
)。
汤姆婚庆(
TomFactory
)汤姆婚庆公司提供具有汤姆特色的业务,如汤姆婚车(
TomCar
)、汤姆婚房(TomHouse
)、汤姆照相(TomPicture
)。public class TomFactory implements MarriageFactory { public TomFactory() { System.out.println("选择了汤姆婚庆公司"); } @Override public Car getCar() { return new TomCar(); } @Override public House getHouse() { return new TomHouse(); } @Override public Picture getPicture() { return new TomPicture(); } }
杰瑞婚庆(
JerryFactory
)杰瑞婚庆公司提供具有杰瑞特色的业务,如杰瑞婚车(
TomCar
)、杰瑞婚房(TomHouse
)、杰瑞照相(TomPicture
)。public class JerryFactory implements MarriageFactory { public JerryFactory() { System.out.println("选择了杰瑞婚庆公司"); } @Override public Car getCar() { return new JerryCar(); } @Override public House getHouse() { return new JerryHouse(); } @Override public Picture getPicture() { return new JerryPicture(); } }
4. 定义具体产品
汤姆婚庆公司提供具有汤姆特色的业务,如汤姆婚车(
TomCar
)、汤姆婚房(TomHouse
)、汤姆照相(TomPicture
)。public class TomCar implements Car{ /** * 婚车 */ @Override public void drive() { System.out.println("汤姆婚车开起来..."); } } public class TomHouse implements House{ /** * 买房 */ @Override public void buyHouse() { System.out.println("汤姆一品房价50w....."); } } public class TomPicture implements Picture{ /** * 照相 */ @Override public void takePicture() { System.out.println("汤姆照相馆照相....."); } }
杰瑞婚庆公司提供的业务具有杰瑞特色,如杰瑞婚车(
TomCar
)、杰瑞婚房(TomHouse
)、杰瑞照相(TomPicture
)。public class JerryCar implements Car{ /** * 婚车 */ @Override public void drive() { System.out.println("杰瑞婚车开起来..."); } } public class JerryHouse implements House{ /** * 买房 */ @Override public void buyHouse() { System.out.println("杰瑞一品房价30w..."); } } public class JerryPicture implements Picture{ /** * 照相 */ @Override public void takePicture() { System.out.println("杰瑞照相馆照相....."); } }
5. 代码演示
下面我们对上述案例进行代码演示
选择杰瑞婚庆公司
public static void main(String[] args) { // 选择杰瑞婚庆公司 MarriageFactory factory = new JerryFactory(); Car car = factory.getCar(); House house = factory.getHouse(); Picture picture = factory.getPicture(); car.drive(); house.buyHouse(); picture.takePicture(); }
输出结果:
选择汤姆婚庆公司
public static void main(String[] args) { // 选择杰瑞婚庆公司 MarriageFactory factory = new TomFactory(); Car car = factory.getCar(); House house = factory.getHouse(); Picture picture = factory.getPicture(); car.drive(); house.buyHouse(); picture.takePicture(); }
输出结果:
6. 代码改造
在上面的测试代码中我们注意到,我们只是对new
婚庆公司的实际类型做了修改,而产品相关代码没有任何改动。于是我们可以将对婚庆公司的实例化过程按照工厂方法设计模式那样转移到工厂中,只需要抽象工厂根据传入的参数返回不同的工厂实例即可。
在抽象工厂中添加静态方法
getInstance()
和 枚举类MarriageType
static MarriageFactory getInstance(MarriageType type) { if (type.equals(MarriageType.JERRY)) { return new JerryFactory(); } return new TomFactory(); } enum MarriageType { JERRY, TOM; }
修改测试代码
public static void main(String[] args) { // 选择杰瑞婚庆公司 MarriageFactory factory = MarriageFactory.getInstance(MarriageFactory.MarriageType.JERRY); Car car = factory.getCar(); House house = factory.getHouse(); Picture picture = factory.getPicture(); car.drive(); house.buyHouse(); picture.takePicture(); }
另外,在静态方法getInstance()
中,我们可以再次结合单例模式来避免频繁实例化婚庆公司对象。
四、总结
- 抽象工厂与工厂方法的最主要区别就是:抽象工厂允许创建多个产品;而工厂方法只允许创建一个产品。
- 该设计模式有一个致命缺点:每当我们在工厂中添加新的产品时,工厂的抽象和具体实现都需要修改。当工厂的具体实现较多时,每一个实现都必须适配新添加的产品。
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————