设计模式之工厂模式

文章目录

一、介绍

工厂模式(Factory Pattern)是最常使用的设计模式之一,属于创建型设计模式 。在该设计模式中,我们不再使用new来实例化对象,而是通过工厂对象 来获取指定的对象实例,其中对象的实例化过程是在工厂中完成的。换句话说,就是将对象的实例化过程从 调用方控制 改变成 工厂控制

说到这里,我愣了一下,这不就是控制反转(IOC)嘛?

大家回忆一下spring框架的IOC容器:spring的IOC容器主要使用的设计模式之一就是工厂模式,它将我们对对象的控制权转移给了BeanFactoryBeanFactory把实例化的对象放在单例池(即容器)中,当我们需要从spring中获取一个对象时,spring直接从该容器中获取对应的实例并返回给我们。

因此,我们使用工厂方法的目的是通过工厂提供一种统一的接口来创建不同类型的对象,将对象的创建过程与对象的使用过程分离,因为对象的创建过程是由工厂负责的,工厂只需要提供一个获取已创建的对象实例的方法。

二、基本组件

在我们使用工厂方法时,一般需要以下组件:

  • 工厂抽象。接口或抽象类,定义了工厂的行为。
  • 工厂实现类。对工厂的行为提供了具体实现。不同的工厂实现类用于创建不同的产品实现类。
  • 产品抽象。作为父类或接口,规定了一类具有相同行为的产品。
  • 产品实现类。产品抽象类的具体实现。

一般来讲,从工厂中获取的对象类型为抽象类型,其具体类型由工厂方法决定。

如下图所示

三、案例应用

我们举一个例子,有一个自行车公司(BicycleFactory) ,主要业务为生产自行车(Bicycle) ,该公司有两个工厂,专门生产哈罗单车(HaLuoBicycle)的工厂(HaLuoBicycleFactory) 和 专门生产美团单车(MeiTuanBicycle)的工厂(MeiTuanBicycleFactory)

其中,自行车公司(BicycleFactory)即为工厂抽象 ,提供create()方法生产自行车。哈罗单车工厂(HaLuoBicycleFactory) 和 美团单车工厂(MeiTuanBicycleFactory)作为工厂实现类 。自行车(Bicycle)为产品抽象 。哈罗单车(HaLuoBicycle) 和 美团单车(MeiTuanBicycle) 作为产品实现类。

如下图所示

1. 代码演示

下面我们通过代码模拟工厂模式的实现

  • 自行车公司(BicycleFactory)

    java 复制代码
    public interface BicycleFactory {
    
        /**
         * 生产单车
         * @return 抽象的单车
         */
        public Bicycle create();
    }
  • 哈罗单车工厂(HaLuoBicycleFactory)

    java 复制代码
    public class HaLuoBicycleFactory implements BicycleFactory {
    
        /**
         * 生产哈罗单车
         * @return 哈罗单车
         */
        @Override
        public Bicycle create() {
            return new HaLuoBicycle();
        }
    }
  • 美团单车工厂(MeiTuanBicycleFactory)

    java 复制代码
    public class MeiTuanBicycleFactory implements BicycleFactory {
    
        /**
         * 生产美团单车
         * @return 美团单车
         */
        @Override
        public Bicycle create() {
            return new MeiTuanBicycle();
        }
    }
  • 自行车(Bicycle)

    java 复制代码
    public interface Bicycle {
        /**
         * 获取颜色
         * @return 颜色
         */
        String getColor();
    
        /**
         * 获取品牌
         * @return 品牌
         */
        String getBrand();
    }
  • 哈罗单车(HaLuoBicycle)

    java 复制代码
    public class HaLuoBicycle implements Bicycle {
    
        private final String color;
        private final String brand;
    
        public HaLuoBicycle() {
            System.out.println("哈罗单车被实例化");
            this.color = "蓝色";
            this.brand = "哈罗";
        }
    
        @Override
        public String getColor() {
            return this.color;
        }
    
        @Override
        public String getBrand() {
            return this.brand;
        }
    }
  • 美团单车(MeiTuanBicycle)

    java 复制代码
    public class MeiTuanBicycle implements Bicycle {
    
        private final String color;
        private final String brand;
    
        public MeiTuanBicycle() {
            System.out.println("美团单车被实例化");
            this.color = "黄色";
            this.brand = "美团";
        }
    
        @Override
        public String getColor() {
            return this.color;
        }
    
        @Override
        public String getBrand() {
            return this.brand;
        }
    }
  • 代码演示

    java 复制代码
    public static void main(String[] args) {
        // 实例化一个美团单车工厂
        BicycleFactory meiTuanFactory = new MeiTuanBicycleFactory();
        // 美团单车工厂生产美团单车
        Bicycle meiTuan = meiTuanFactory.create();
        System.out.println(meiTuan.getColor());
        System.out.println(meiTuan.getBrand());
    
    	// 实例化一个哈罗单车工厂
        BicycleFactory haLuoFactory = new HaLuoBicycleFactory();
        // 哈罗单车工厂生产哈罗单车
        Bicycle haluo = haLuoFactory.create();
        System.out.println(haluo.getColor());
        System.out.println(haluo.getBrand());
    
    }
  • 输出结果

2. 优缺点

从上面的代码演示中,我们可以总结出以下优缺点

优点:

  • 对象的创建过程与使用过程被解耦。如果被创建的对象结构复杂,则可以在工厂方法中完成该对象结构的组装。
  • 工厂方法返回的是产品抽象。因此我们无需关注产品细节,只需要按照产品抽象所定义的方法进行方法调用即可。
  • 当产品的创建过程需要修改时,我们只需在工厂方法中对创建逻辑进行修改即可,无需修改调用方的代码。
  • 适用于结构复杂的对象的创建场景。

缺点:

  • 虽然我们不再关注对象的创建过程,但是代价是需要关注工厂实例的创建过程。其实无论从代码层面还是现实层面来说,工厂对象一般只有一个,我们需要结合单例模式来处理对象工厂的创建和获取逻辑。
  • 一个工厂对象仅能创建一种产品。
  • 每当新增一个产品时,同样也需要创建对应的工厂类。这会导致项目中积累大量的工厂类和产品类。
  • 不适用于简单对象的创建。原本只需一行代码就能完成,而使用工厂模式就需要创建工厂类、工厂方法等,增加代码量。

四、静态工厂

由于工厂模式一般适用于创建复杂对象的场景。当我们需要创建简单对象时,使用工厂模式无疑是一种杀鸡用牛刀的方式。

静态工厂模式是工厂模式的衍生设计模式,用于创建简单的对象。

在静态方法中,只需要一个具体的产品类以及获取对应对象实例的静态方法。

使用上面的案例,我们以**美团单车(MeiTuanBicycle)**为例。在该类中添加一个静态方法create(),如下所示

java 复制代码
public class MeiTuanBicycle implements Bicycle {

    private final String color;
    private final String brand;

    public MeiTuanBicycle() {
        System.out.println("美团单车被实例化");
        this.color = "黄色";
        this.brand = "美团";
    }

    @Override
    public String getColor() {
        return this.color;
    }

    @Override
    public String getBrand() {
        return this.brand;
    }

    /**
     * 静态工厂
     * @return
     */
    public static Bicycle create() {
        return new MeiTuanBicycle();
    }
}


public static void main(String[] args) {

    // 静态方法
    Bicycle bicycle = MeiTuanBicycle.create();
    System.out.println(bicycle.getColor());
    System.out.println(bicycle.getBrand());
}

输出结果如下:

1. 应用

静态工厂在jdk中的应用十分广泛,例如Integer.parseInt()方法:

java 复制代码
public final class Integer extends Number implements Comparable<Integer> {
    // ...
    public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
    }
    // ...
}

在该静态方法中,Integer类是工厂 ,它的静态方法parseInt接收字符串作为参数,返回一个Integer对象,因此Integer类又是产品

五、总结

本文介绍了创建型设计模式中的工厂模式 和它的衍生设计模式静态工厂模式。并通过具体案例对其讲解,现在对这两中设计模式进行优缺点总结:

  • 工厂模式

    适用于创建复杂对象 的场景,并将其创建过程和使用过程解耦

    • 优点
      • 对象的创建过程与使用过程被解耦。如果被创建的对象结构复杂,则可以在工厂方法中完成该对象结构的组装。
      • 工厂方法返回的是产品抽象。因此我们无需关注产品细节,只需要按照产品抽象所定义的方法进行方法调用即可。
      • 当产品的创建过程需要修改时,我们只需在工厂方法中对创建逻辑进行修改即可,无需修改调用方的代码。
      • 适用于结构复杂的对象的创建场景。
    • 缺点
      • 虽然我们不再关注对象的创建过程,但是代价是需要关注工厂实例的创建过程。其实无论从代码层面还是现实层面来说,工厂对象一般只有一个,我们需要结合单例模式来处理对象工厂的创建和获取逻辑。
      • 一个工厂对象仅能创建一种产品。
      • 每当新增一个产品时,同样也需要创建对应的工厂类。这会导致项目中积累大量的工厂类和产品类。
      • 不适用于简单对象的创建。原本只需一行代码就能完成,而使用工厂模式就需要创建工厂类、工厂方法等,增加代码量。
  • 静态工厂模式

    适用于创建复杂对象的场景。

    • 优点
      • 简单

纸上得来终觉浅,绝知此事要躬行。

------------------------我是万万岁,我们下期再见------------------------

相关推荐
CT随7 分钟前
Redis内存碎片详解
java·开发语言
brrdg_sefg16 分钟前
gitlab代码推送
java
hanbarger39 分钟前
mybatis框架——缓存,分页
java·spring·mybatis
cdut_suye1 小时前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
苹果醋31 小时前
2020重新出发,MySql基础,MySql表数据操作
java·运维·spring boot·mysql·nginx
小蜗牛慢慢爬行1 小时前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
azhou的代码园1 小时前
基于JAVA+SpringBoot+Vue的制造装备物联及生产管理ERP系统
java·spring boot·制造
捕鲸叉1 小时前
C++软件设计模式之外观(Facade)模式
c++·设计模式·外观模式
小小小妮子~1 小时前
框架专题:设计模式
设计模式·框架
先睡1 小时前
MySQL的架构设计和设计模式
数据库·mysql·设计模式