概念
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
工厂方法模式结构图:
- Product:抽象产品。所有的具体产品都必须实现这个接口。
- ConcreteProduct:具体产品。实现Product接口。
- Creator:抽象工厂。定义工厂方法来获得产品。
- ConcreateCreator:具体工厂。实现抽象工厂,负责返回具体的产品。
模式实现
小马哥附近的车厂,除了生产宝马、奔驰、奥迪之外又扩展了新的业务,新增生产法拉利和兰博基尼。 简单工厂模式必须对车厂内部进行修改,来满足业务需求:
违反开闭原则,不利于代码的维护。下面我们来进行改进:
一个车厂只生产一种车(这就是工厂方法模式)。
抽象车接口(Product):
public interface Car {
/**
* 启动
*/
void start();
}
具体的车(ConeretProduct)「宝马、奔驰、奥迪、法拉利、兰博基尼」:
public class BmwCar implements Car {
@Override
public void start() {
System.out.println("宝马启动了");
}
}
public class BenzCar implements Car {
@Override
public void start() {
System.out.println("奔驰启动了");
}
}
public class AudiCar implements Car {
@Override
public void start() {
System.out.println("奥迪启动了");
}
}
public class FerrariCar implements Car {
@Override
public void start() {
System.out.println("法拉利启动了");
}
}
public class LamborghiniCar implements Car {
@Override
public void start() {
System.out.println("兰博基尼启动了");
}
}
抽象车厂接口(Creator):
public interface IFactory {
/**
* 返回一个车对象
* @return 车
*/
Car getCar();
}
具体的车厂(ConcreteCreator)「宝马、奔驰、奥迪、法拉利、兰博基尼」:
public class BmwCarFactory implements IFactory {
@Override
public Car getCar() {
return new BmwCar();
}
}
public class BenzCarFactory implements IFactory {
@Override
public Car getCar() {
return new BenzCar();
}
}
public class AudiCarFactory implements IFactory {
@Override
public Car getCar() {
return new AudiCar();
}
}
public class FerrariCarFactory implements IFactory {
@Override
public Car getCar() {
return new FerrariCar();
}
}
public class LamborghiniCarFactory implements IFactory {
@Override
public Car getCar() {
return new LamborghiniCar();
}
}
买一俩兰博基尼回家:
public class Test {
public static void main(String[] args) {
IFactory iFactory = new LamborghiniCarFactory();
Car car = iFactory.getCar();
car.start();
}
}
来看一下UML类图:
优点
- 在工厂方法中,用户只需要知道所要产品的具体工厂,无需关心具体的创建过程,甚至不需要知道具体产品类的类名。
- 在系统增加新的产品时,我们只需要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”。
缺点
- 每增加一个产品时,都需要增加一个具体类和对象实现工厂,系统中类的个数成倍增加,在一定程度上增加了系统的复杂度。
适用场景
- 一个类不需要知道具体产品类,只需要知道创建它的具体工厂即可。
- 将创建对象的任务委托给多个工厂子类中的某一个,客户端使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定。
总结
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点「不符合开闭原则」。但缺点是由于每加一个产品,就需要一个产品工厂的类,增加了额外的开发量和系统复杂度。
源码解析(Logback 1.2.3)
LoggerFactory.getLogger(name)方法,通过getILoggerFactory()方法来获得具体的工厂,然后再调用工厂方法来获得具体的产品:
抽象工厂 | 抽象产品 |
---|---|
ILoggerFactory | Logger |
具体工厂 | 具体产品 |
---|---|
SubstituteLoggerFactory | SubstituteLogger |
NOPLoggerFactory | NOPLogger |
LoggerContext | Logger(实体类,不是接口Logger) |
public final class LoggerFactory {
//省略无关代码...
public static Logger getLogger(String name) {
//获得具体工厂
ILoggerFactory iLoggerFactory = getILoggerFactory();
//获得具体产品并返回
return iLoggerFactory.getLogger(name);
}
}