工厂方法模式

472 阅读3分钟

概念

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

工厂方法模式结构图:

  • 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()方法来获得具体的工厂,然后再调用工厂方法来获得具体的产品:

抽象工厂抽象产品
ILoggerFactoryLogger
具体工厂具体产品
SubstituteLoggerFactorySubstituteLogger
NOPLoggerFactoryNOPLogger
LoggerContextLogger(实体类,不是接口Logger)
public final class LoggerFactory {

    //省略无关代码...
    public static Logger getLogger(String name) {
         //获得具体工厂
         ILoggerFactory iLoggerFactory = getILoggerFactory();
         //获得具体产品并返回
         return iLoggerFactory.getLogger(name);
    }
}