三种工厂模式的优缺点
本文将分别实现简单工厂模式–>工厂方法模式–>抽象工厂模式,并比较其优缺点。
简单工厂模式
定义:由一个工厂对象决定创建出哪一种产品实例
- 不属于GOF23种设计模式中
类型:创建型设计模式
适用场景:
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象逻辑并不关心
Coding
public class SimpleFactoryMain {
/**
* Car接口
*/
interface Car {
/**
* 行驶
*/
void run();
}
/**
* 奥迪车
*/
static class AudiCar implements Car {
@Override
public void run() {
System.out.println("奥迪车行驶速度150km/h");
}
}
/**
* 保时捷
*/
static class PorscheCar implements Car {
@Override
public void run() {
System.out.println("保时捷行驶速度200km/h");
}
}
/**
* 工厂接口
*/
interface CarFactory {
Car create(String name);
}
/**
* 工厂类实现
*/
static class DefaultCarFactory implements CarFactory {
/**
* 优点:
* 对外屏蔽具体的实现细节,外界不需要关心里面的实现逻辑,使用者只需要放心的使用
* 将生产者和消费者进行责任分割
*
* 缺点:
* 无法灵活地应对产品的增加,比如后面需要增加其他的Car,无法避免修改代码的情况下实现功能,
* 而且会造成整个实现方法越来越复杂,直至无法维护
* @param name
* @return
*/
@Override
public Car create(String name) {
if (Objects.equals(name, "Audi")) {
return new AudiCar();
} else if (Objects.equals(name, "Porsche")) {
return new PorscheCar();
}
return null;
}
}
/**
* 主函数
*
* @param args
*/
public static void main(String[] args) {
CarFactory carFactory = new DefaultCarFactory();
Car car = carFactory.create("Audi");
car.run();
car = carFactory.create("Porsche");
car.run();
}
UML
优点:
- 对外屏蔽具体的实现细节,外界不需要关心里面的实现逻辑,使用者只需要放心的使用
- 将生产者和消费者进行责任分割
缺点:
- 无法灵活地应对产品的增加,比如后面需要增加其他的Car,无法避免修改代码的情况下实现功能,
- 而且会造成整个实现方法越来越复杂,直至无法维护
框架中的简单工厂模式
- JDk中:
- Calendar.createCalendar()
- Calendar.createCalendar()
- JDBC中
- DriverManager.getConnection()
- logback中
- LoggerContext.getLogger()
拓展知识:基于反射升级简单工厂模式
- coding
public class SimpleFactoryMain {
/**
* Car接口
*/
interface Car {
/**
* 行驶
*/
void run();
}
/**
* 奥迪车
*/
static class AudiCar implements Car {
@Override
public void run() {
System.out.println("奥迪车行驶速度150km/h");
}
}
/**
* 保时捷
*/
static class PorscheCar implements Car {
@Override
public void run() {
System.out.println("保时捷行驶速度200km/h");
}
}
/**
* 工厂接口
*/
interface CarFactory {
Car create(String name);
// 基于反射升级简单工厂模式
Car create(Class clazz);
}
/**
* 工厂类实现
*/
static class DefaultCarFactory implements CarFactory {
/**
* 优点:
* 对外屏蔽具体的实现细节,外界不需要关心里面的实现逻辑,使用者只需要放心的使用
* 将生产者和消费者进行责任分割
*
* 缺点:
* 无法灵活地应对产品的增加,比如后面需要增加其他的Car,无法避免修改代码的情况下实现功能,
* 而且会造成整个实现方法越来越复杂,直至无法维护
* @param name
* @return
*/
@Override
public Car create(String name) {
if (Objects.equals(name, "Audi")) {
return new AudiCar();
} else if (Objects.equals(name, "Porsche")) {
return new PorscheCar();
}
return null;
}
/**
* 基于反射升级简单工厂模式
* 优点:在上面基础上升级,当增加其他的Car时,系统无需扩展工厂的代码,只需要实现Car,
* 因此符合开闭原则。
**/
@Override
public Car create(Class clazz) {
try {
return (Car) clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
/**
* 主函数
*
* @param args
*/
public static void main(String[] args) {
CarFactory carFactory = new DefaultCarFactory();
Car car = carFactory.create("Audi");
car.run();
car = carFactory.create("Porsche");
car.run();
car = carFactory.create(AudiCar.class);
car.run();
car = carFactory.create(PorscheCar.class);
car.run();
}
- 优点:在上面基础上升级,当增加其他的Car时,系统无需扩展工厂的代码,只需要实现Car,因此符合开闭原则。
工厂方法模式
描述:
正是因为简单工厂的缺点,使用一个工厂类无法应对多样的产品变化,导致代码的维护越来越困难,脱离了设计模式的初衷。所以针对后期可能出现的多样产品,我们尝试使用一下工厂方法解决问题。
定义:
- 一个用于创建对象的接口,让子类决定将哪一个类实例化。使一个类的实例化延迟到其子类
适用场景
- 创建代码需要大量重复的代码
- 客户端(应用层)不依赖产品实例如何被创建、实现等细节
- 一个类通过其子类来指定创建哪个对象
coding
public class FactoryMethodMain {
/**
* Car接口
*/
interface Car {
/**
* 行驶
*/
void run();
}
/**
* 奥迪车
*/
static class AudiCar implements Car {
@Override
public void run() {
System.out.println("奥迪车行驶速度150km/h");
}
}
/**
* 保时捷
*/
static class PorscheCar implements Car {
@Override
public void run() {
System.out.println("保时捷行驶速度200km/h");
}
}
/**
* 工厂接口
*/
interface CarFactory {
/**
* 生产车
*
* @return
*/
Car create();
}
/**
* 奥迪工厂类实现
*/
static class AudiCarFactory implements CarFactory {
/**
* @return
*/
@Override
public Car create() {
return new AudiCar();
}
}
/**
* 保时捷工厂类实现
*/
static class PorscheCarFactory implements CarFactory {
/**
* @return
*/
@Override
public Car create() {
return new PorscheCar();
}
}
/**
* 主函数
*
* @param args
*/
public static void main(String[] args) {
//奥迪车工厂
CarFactory carFactory1 = new AudiCarFactory();
Car car = carFactory1.create();
car.run();
/**
* 保时捷工厂
*/
CarFactory carFactory2 = new PorscheCarFactory();
car = carFactory2.create();
car.run();
}
}
UML
基于工厂方法的设计思想,即使有再多的产品需要加入进来,也是可以通过不断地创建对应的工厂类进行生产,完全不需要担心修改或维护非常复杂的创建逻辑
优点
- 用户只需关系所需产品对应的工厂,无需关心创建细节
- 加入新产品符合开闭原则,提高可扩展性
缺点
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性, 理解难度
框架中的工厂方法模式:
- Jdk 中
// 所有实现Collection接口的实现类都需要实现iterator()方法
// 不同的子类需要创建不同的Iterator子类
public interface Collection<E> extends Iterable<E> {
Iterator<E> iterator();
}
抽象工厂模式
描述:
工厂方法和抽象工厂最大的区别在于,工厂方法针对于一个产品等级结构,而抽象工厂针对于多个产品等级结构。
概述
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
适用场景
客户端(应用层)不依赖产品实例如何被创建、实现等细节
强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复代码
提供一个产品类的库,所有的产品以同样的接口出现,从而客户端不依赖与具体实现
Coding
public class AbstractFactoryMain {
/**
* Car接口
*/
interface Car {
/**
* 行驶
*/
void run();
}
/**
* 奥迪车
*/
static class AudiCar implements Car {
@Override
public void run() {
System.out.println("奥迪车行驶速度150km/h");
}
}
/**
* 保时捷
*/
static class PorscheCar implements Car {
@Override
public void run() {
System.out.println("保时捷行驶速度200km/h");
}
}
/**
* 发动机
*/
interface Engine {
void run();
}
/**
* 奥迪发动机
*/
static class AudiEngine implements Engine {
@Override
public void run() {
System.out.println("奥迪发动机在运行");
}
}
/**
* 保时捷发动机
*/
static class PorscheEngine implements Engine {
@Override
public void run() {
System.out.println("保时捷发动机在运行");
}
}
/**
* 工厂接口
*/
interface CarFactory {
/**
* 生产车
*
* @return
*/
Car createCar();
/**
* 生产发动机
*
* @return
*/
Engine createEngine();
}
/**
* 奥迪工厂类实现
*/
static class AudiCarFactory implements CarFactory {
/**
* @return
*/
@Override
public Car createCar() {
return new AudiCar();
}
@Override
public Engine createEngine() {
return new AudiEngine();
}
}
/**
* 保时捷工厂类实现
*/
static class PorscheCarFactory implements CarFactory {
/**
* @return
*/
@Override
public Car createCar() {
return new PorscheCar();
}
@Override
public Engine createEngine() {
return new PorscheEngine();
}
}
/**
* 主函数
*
* @param args
*/
public static void main(String[] args) {
//奥迪车工厂
CarFactory carFactory1 = new AudiCarFactory();
Car car = carFactory1.createCar();
car.run();
Engine engine1 = carFactory1.createEngine();
engine1.run();
/**
* 保时捷工厂
*/
CarFactory carFactory2 = new PorscheCarFactory();
car = carFactory2.createCar();
car.run();
Engine engine2 = carFactory2.createEngine();
engine2.run();
}
优点
具体产品在应用层代码隔离,无需关心创建细节
讲一个系列的产品族放在一起
缺点
规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
增加了系统的抽象性和理解难度