工厂方法模式:改变你对软件开发的认知

60 阅读7分钟

3.jpg

什么是工厂方法模式?

工厂方法模式是一种类创建型模式,它定义了一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式简称为工厂模式,又可称为虚拟构造模式或多态工厂模式。

在工厂方法模式中,抽象产品是定义产品的接口,它是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。具体工厂是抽象工厂的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例。

基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节完全封装在具体工厂内部。所有的具体工厂类都具有同一个抽象父类。

与简单工厂模式有什么区别?

工厂方法模式与简单工厂模式的主要区别在于它们实现产品或对象创建的方式。

简单工厂模式的特点是,它使用一个具体工厂类(包含业务逻辑和创建对象),根据外界给定的原料,加上自身封装好的判断,来生产出不同类型的相应产品或对象。这种模式的问题在于,它很容易违反高内聚低耦合原则,尤其是在产品或对象创建逻辑复杂的情况下。因此,简单工厂模式通常只在产品或对象创建逻辑很简单的情况下应用。

相比之下,工厂方法模式的核心是一个抽象工厂类。在这个模式中,“工厂”创建的是还没有分化好的对象,其中没有逻辑判断。工厂方法模式让子类去决定具体实例化的对象,把简单的内部逻辑判断移到了客户端代码。

当系统需要加入一个新的产品时,只需要向系统中加入一个这个产品类似及它所对象的工厂类,而没有必要修改客户端,也没有必要修改抽象工厂角色或者其他也有的具体工厂角色,在设计上完全符合设计模式的六大设计原则中的开闭原则。因此,工厂方法模式对于业务变化比较大的场景是适用的。

总的来说,简单工厂模式和工厂方法模式的主要区别在于产品或对象的创建方式:简单工厂模式是在一个具体工厂类中实现创建过程,而工厂方法模式则是通过抽象工厂类和子工厂类来共同完成创建过程。

工厂方法模式的UML类图

工厂方法模式的UML类图通常由以下四个角色组成:

  • 抽象工厂(Factory):这是工厂方法模式的核心,创建的对象的工厂类需要实现这个接口。
  • 具体工厂(Concrete Factory):这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且被应用程序调用以创建产品对象。
  • 抽象产品(Product):这是工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
  • 具体产品(Concrete Product):这个角色实现了抽象产品角色所定义的接口。

UML类图中不同的箭头和线条,代表的意义是不同的,这里简单的梳理了一下,如果需要可以移步这里:掌握UML类图:打开系统设计的新视界 - 掘金 (juejin.cn)

image.png

工厂方法模式示例

还接着上篇文章《掌握简单工厂模式:高效开发的必备利器 - 掘金 (juejin.cn)》女娲造人的传说来演示一下工厂方法模式的示例:

1、定义一个抽象人类Human,Man.java、Woman.java分别实现Human;

2、定义一个抽象工厂类HumanFactory,ManFactory.java、WomanFactory.java是两个可以生成男人、女人的工厂类,分别实现了HumanFactory接口;

3、然后就可以分别开动ManFactory、WomanFactory开始造人了;

抽象产品

public interface Human {
    /**
     * 人类会吃东西
     */
    void eat();

    /**
     * 人类会喝东西
     */
    void drink();
}

具体产品1:

public class Man implements Human{
    @Override
    public void eat() {
        System.out.println("男人一般比较喜欢吃肉");
    }

    @Override
    public void drink() {
        System.out.println("男人一般比较喜欢喝酒");
    }
}

具体产品2:

public class Woman implements Human{
    @Override
    public void eat() {
        System.out.println("女人一般都比较喜欢吃甜食");
    }

    @Override
    public void drink() {
        System.out.println("女人一般都比较喜欢喝红酒");
    }
}

抽象工厂

public interface HumanFactory {
    /**
     * 造人
     * @return
     */
    Human create();
}

具体工厂1

public class ManFactory implements HumanFactory{
    @Override
    public Human create() {
        return new Man();
    }
}

具体工厂2

public class WoManFactory implements HumanFactory{
    @Override
    public Human create() {
        return new Woman();
    }
}

image.png

public class Test {
    public static void main(String[] args) {
        HumanFactory manFactory=new ManFactory();
        Human man=manFactory.create();
        man.eat();
        man.drink();
        HumanFactory womanFactory=new WoManFactory();
        Human woman=womanFactory.create();
        woman.eat();
        woman.drink();
    }
}

4、如果要造机器人怎么办呢?再建一个机器人的工厂,实现HumanFactory接口就可以了;

public class Test {
    public static void main(String[] args) {
        HumanFactory robotFactory=new RobotFactory();
        Human robot=robotFactory.create();
        robot.drink();
        robot.eat();
    }
}

image.png

工厂方法模式在Spring、Mybatis中的应用

  1. BeanFactory:Spring的BeanFactory类就是一个工厂模式的实现,它用于创建并管理Java对象。BeanFactory是一个接口,Spring框架中实现了这个接口的类有很多,例如ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory等。
  2. ServiceFactory:ServiceFactory是用于创建Java服务的工厂,它可以简化服务的创建和使用过程,提高代码的可维护性和可重用性。
  3. ProxyFactory:ProxyFactory是Spring框架中用于创建代理对象的工厂,它可以通过AOP(Aspect Oriented Programming)将程序的行为分成不同的方面,提高程序的模块化和可维护性。
  4. SqlSessionFactory:SqlSessionFactory是用于创建Java中MyBatis框架的SqlSession对象的工厂,通过SqlSessionFactory可以获取SqlSession对象,进而执行数据库操作。
  5. DataSource:DataSource是用于获取数据库连接的工厂,它可以通过JNDI或者Spring配置文件中的bean定义来获取数据源对象,进而获取数据库连接。

总结

工厂方法模式具有以下优点:

  1. 工厂方法模式遵循了“开闭原则”,当需要添加新的产品时,只需要增加新的具体工厂和具体产品类,无需修改原有的代码,符合“开放-封闭原则”。
  2. 工厂方法模式将对象的创建和使用分离,客户端只需要知道抽象工厂和抽象产品,就可以创建所需的产品对象,客户端使用更方便。
  3. 工厂方法模式可以将客户端与具体类的创建过程分离,使得客户端无需关注对象的创建细节,更无需知道具体产品类的类名,客户端可以更加专注于自身的业务逻辑。
  4. 工厂方法模式通过多态性,使得工厂方法可以创建不同的具体产品对象,提高了系统的灵活性。

然而,工厂方法模式也存在一些缺点:

  1. 工厂方法模式需要在每个具体工厂中实现抽象工厂中的所有方法,这会增加代码的复杂度和维护成本。
  2. 如果需要创建的对象种类非常多,工厂方法模式会导致工厂类数量变得很庞大,这不利于代码的管理和维护。
  3. 工厂方法模式会打破“开闭原则”,当需要添加新的产品时,需要增加新的具体工厂和具体产品类,这会增加代码的侵入性。
  4. 工厂方法模式可能会违反“单一职责原则”,因为工厂类既要负责创建对象,也要负责管理对象之间的关系,这会导致代码的职责不清晰,不利于代码的维护和重构。