引言
工厂模式(Factory Pattern)是最常用的设计模式之一,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。工厂模式可以分为三种:简单工厂模式,工厂方法模式,抽象工厂模式。我们以汽车工厂生产汽车为例,对这三种工厂模式进行说明。
一.简单工厂模式
简单工厂模式的特点是调用者通过一个具体的工厂类获取所需要产品,而不需要关心该产品具体的生产过程。
UML类图
- Product:抽象产品类,简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
- ConcreteProduct:具体产品类,是简单工厂模式的创建目标。
- ProductFactory:产品工厂类,简单工厂模式的核心,它负责实现创建所有产品的具体逻辑。调用者通过调用其方法获取到自己想要的产品。
demo代码演示
我们以生产汽车为例,用简单代码进行说明。
//抽象产品类定义,汽车类
interface Car{
void run();
}
//具体产品类定义,奥迪车
public class Audi implement Car{
public void run(){
System.out.println("奥迪汽车启动");
}
}
//具体产品类定义,奔驰车
public class Benz implement Car{
public void run(){
System.out.println("奔驰汽车启动");
}
}
//工厂类定义,汽车工厂,负责实例化各种品牌汽车
public class CarFactory{
public static Car getCar(String brand){
Car car = null;
if(brand.equals("audi")){
//生产奥迪车
car = new Audi() ;
}else if(brand.equals("benz")){
//生产奔驰车
car = new Benz() ;
}
return car ;
}
}
//消费者类,从工厂获取到需要的产品
public class Client{
public static void main(String[] args){
//消费者调用工厂方法,只需要传入自己想要的汽车品牌名便可以获得相应的汽车,无需关心产品的创建逻辑
Car myCar = CarFactory.getCar("audi");
//Car myCar = CarFactory.getCar("benz");
myCar.run();
}
}
模式优缺点
- 优点:
使用户根据参数获得对应的类实例,避免了直接实例化类,降低了耦合性。 - 缺点:
所有产品的创建都放在一个工厂中,工厂类的职责过重。如果增加新的产品类型,则需要修改工厂,违背了开闭原则 。当产品类型越来越多时,工厂类的代码量会越来越庞大,不利于阅读和维护。
工厂方法模式
简单工厂模式虽然简单,但是存在一个非常严重的问题,即当系统引入新的产品类型时,我们就不得不去修改工厂类的源代码,这违背了开闭原则,如何在增加产品类型的同时不影响原来的工厂代码呢?工厂方法模式应运而生。
工厂方法模式是将工厂类抽象出一个接口,这个接口中有一个创建抽象产品的方法。然后,所有要生产具体产品类的工厂去实现这个抽象工厂接口。既,将一个简单工厂模式的工厂类变成了一个抽象工厂接口和多个具体工厂实现类,如果要增加新的产品,只需要增加该产品的具体生产工厂类即可,而不需要去修改原有的工厂类,这样便实现了开闭原则。
UML类图
- AbstractFactory:抽象工厂类,它是所有具体工厂类的父类,它负责描述生产抽象产品的公共接口。
- ConcreteFactory1 / ConcreteFactory2:具体工厂类,实现抽象工厂接口,负责具体产品的生产
- AbstractProduct:抽象产品类,它是所有具体产品类的父类,负责描述抽象产品的公共属性
- ConcreteProduct1 / ConcreteProduct2:具体产品类,实现抽象产品接口。
- Client:消费者,从工厂获得需要的产品
demo代码演示
//抽象产品类定义,汽车类
interface Car{
void run();
}
//具体产品类定义,奥迪车
public class AudiCar implements Car{
public void run(){
System.out.println("奥迪汽车启动");
}
}
//具体产品类定义,奥迪车
public class AudiCar implements Car{
public void run(){
System.out.println("奥迪汽车启动");
}
}
//抽象工厂类定义
public interface CarFactory{
Car createCar();
}
//具体工厂类定义,奥迪车工厂
public class AudiCarFactory implements CarFactory{
//实现抽象工厂方法,生产奥迪车
public Car createCar(){
return new AudiCar();
}
}
//具体工厂类定义,奔驰车工厂
public class AudiCarFactory implements CarFactory{
//实现抽象工厂方法,生产奔驰车
public Car createCar(){
return new BenzCar();
}
}
//消费者类,从工厂获取到需要的产品
public class Client{
public static void main(String[] args){
//获得奥迪车
CarFactory carFactory = new AudiCarFactory();
Car myCar = carFactory.createCar();
myCar.run();
//获得奔驰车
将CarFactory carFactory = new AudiCarFactory()改为
CarFactory carFactory = new BenzCarFactory()即可
}
}
模式优缺点
- 优点
增加新的产品时,只需要增加一个具体工厂类,不需要修改原有工厂,保证了开闭原则。
- 缺点
增加新的产品时,需要添加对应的工厂类,系统中的类的个数会成对增加,在一定程度上增加了系统的复杂度;类的增多就有更多的类需要编译,增加系统的开销
三.抽象工厂模式
消费者在购买汽车时,除了会关心汽车品牌,对同一品牌汽车的配置也会有要求。有的消费者财大气粗,喜欢高配奥迪车,有的则追求性价比,更倾向于标配奥迪车。这就要求工厂必须能够生产不同等级不同品牌的汽车。
工厂方法模式中的每个具体工厂都只能生产一种产品,如果使用工厂方法模式实现上述需求,则需要4个具体工厂来分别生产高配奥迪车、标配奥迪车、高配奔驰车、标配奔驰车。为了降低系统复杂性,减少系统中工厂类的个数,就需要用到抽象工厂模式。
抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一系列产品。抽象工厂模式定义如下:
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
UML类图
● Factory(抽象工厂):它声明了一组用于创建一系列产品的方法,每个方法对应一种产品的生产。
● ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
● AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
● ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法
demo代码演示
//抽象产品定义,奥迪汽车
interface AudiCar{
void run();
}
//具体产品定义,高配奥迪车
class HighEndAudiCar implements AudiCar{
void run(){
System.out.println("高配奥迪车启动");
}
}
//具体产品定义,标配奥迪车
class StanAudiCar implements BenzCar{
void run(){
System.out.println("标配奥迪车启动");
}
}
//抽象产品定义,奔驰汽车
interface BenzCar{
void run();
}
//具体产品定义,高配奔驰车
class HighEndBenzCar implements BenzCar{
void run(){
System.out.println("高配奔驰车启动");
}
}
//具体产品定义,奔驰奥迪车
class StanBenzCar implements BenzCar{
void run(){
System.out.println("标配奔驰车启动");
}
}
//抽象工厂定义,该工厂既可以生产奥迪车也可以生产奔驰车
interface CarFactory{
AudiCar createAudiCar();
BenzCar createBenzCar();
}
//具体工厂定义,高配车工厂,该工厂生产高配车系列
class HingEndCarFactory implements CarFactory{
//生产高配奥迪车
AudiCar createAudiCar(){
return new HighEndAudiCar();
}
//生产高配奔驰车
BenzCar createBenzCar(){
return new HighEndBenzCar();
}
}
//具体工厂定义,标配车工厂,该工厂生产标配车系列
class StanCarFactory implements CarFactory{
//生产标配奥迪车
AudiCar createAudiCar(){
return new StanAudiCar();
}
//生产标配奔驰车
BenzCar createBenzCar(){
return new StanBenzCar();
}
}
//消费者调用示例
public class Client{
public static void main(String[] args){
//获取高配车系列
CarFactory factory = new HighEndCarFactory();
AudiCar myAudi = factory.createAudiCar();
myAudi.run();
BenzCar myBenz = factory.createBenzCar();
myBenz.run();
//获得标配车系列
将CarFactory factory = new HighEndCarFactory()修改为
CarFactory factory = new StanCarFactory()即可
}
}
模式优缺点
- 优点
将一系列产品放在同一个工厂中生产,能够保证客户端始终只使用同一系列的产品。
增加新的产品系列很方便, 无须修改已有系统, 符合开闭原则。比如上述例子中增加低配车系列,只需要增加低配车具体类和低配工厂具体类即可,无需修改原有的代码。
- 缺点
增加新的产品类型麻烦, 需要对原有系统进行较大的修改, 甚至需要修改抽象层代码, 违背了开闭原则。比如上述例子中增加宝马品牌的汽车,则需要修改抽象工厂类和所有的具体工厂类。
参考资料
通过实例说设计模式——工厂方法模式(Factory Method Pattern)