设计模式系列:工厂模式

一、核心概念

工厂模式 = "对象的'生产车间'" 核心逻辑:把 "创建对象" 的活儿,从客户端手里抢过来,交给专门的 "工厂类" 干------ 客户端不用知道对象是怎么 new 出来的、内部逻辑是什么,只要告诉工厂 "我要什么",工厂直接把造好的对象扔给你用。

二、解决的核心痛点(为什么不能直接 new,非要用工厂?)

工厂模式解决 3 个核心问题:

  1. 创建逻辑太复杂,客户端扛不住:如果一个对象创建要写 10 行代码(比如初始化参数、连接资源、校验规则),每个客户端都要写一遍,重复代码爆炸;
  2. 对象类型可能变,改代码改到吐 :比如原来用MySQLConnection,后来要换成OracleConnection,如果所有客户端都直接new MySQLConnection(),得一个个改;
  3. 客户端不需要知道 "怎么造",只需要 "怎么用":你买手机不用知道芯片怎么焊、系统怎么装,店里(工厂)给你成品就行 ------ 对象也一样。

三、核心角色

工厂模式的 4 个核心角色,每个角色各司其职,分工明确:

角色名称 通俗解释(类比现实) 工厂模式中具体例子(Shape 案例)
抽象产品(Abstract Product) 所有产品的 "通用说明书":规定产品必须有哪些功能 Shape接口(规定必须有draw()方法)
具体产品(Concrete Product) 符合说明书的 "具体商品":实现通用功能 CircleRectangleSquare(各自实现draw()
抽象工厂(Abstract Factory) 工厂的 "通用营业执照":规定工厂必须能造哪些产品 (简单工厂没有这个角色,工厂方法 / 抽象工厂才有)比如ShapeFactory接口(规定必须有getShape()方法)
具体工厂(Concrete Factory) 真正的 "生产车间":按说明书造具体商品 ShapeFactory类(实现getShape(),造具体形状)

👉 补充:简单工厂模式没有 "抽象工厂",直接用 "具体工厂" 干所有活(入门款);工厂方法 / 抽象工厂是进阶款,多了 "抽象工厂" 来适配更多产品类型(后面会说)。

四、工作流程

工厂模式的流程比较简单,3 步搞定:

  1. 客户端提需求 :客户端不自己new对象,而是找工厂说 "我要一个圆形(CIRCLE)";
  2. 工厂搞生产 :工厂接收需求,按自己的逻辑(比如判断参数)创建对应的具体产品对象(new Circle());
  3. 客户端直接用 :工厂把造好的对象返回给客户端,客户端只需要调用对象的方法(shape.draw()),完全不管对象是怎么造出来的。

👉 工厂模式流程是:客户端发需求→工厂创建产品→返回产品→客户端使用。

五、代码示例

第一步:定义 "抽象产品"(通用说明书)
复制代码
// 抽象产品:Shape接口(规定所有形状必须能"画")
public interface Shape {
    void draw(); // 通用功能:画自己
}
第二步:定义 "具体产品"(具体商品)
复制代码
// 具体产品1:圆形(符合Shape说明书,实现draw())
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画了一个圆形");
    }
}

// 具体产品2:矩形(同理)
public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画了一个矩形");
    }
}

// 具体产品3:正方形(同理)
public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("画了一个正方形");
    }
}
第三步:定义 "具体工厂"(生产车间)
复制代码
// 具体工厂:ShapeFactory(负责造所有Shape产品)
public class ShapeFactory {
    // 生产方法:接收需求(形状名称),返回造好的产品
    public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null; // 没需求,不生产
        }
        // 按需求造对应产品(工厂的核心生产逻辑)
        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
            return new Rectangle();
        } else if (shapeType.equalsIgnoreCase("SQUARE")) {
            return new Square();
        }
        return null; // 没有对应产品
    }
}
第四步:客户端调用
复制代码
public class FactoryDemo {
    public static void main(String[] args) {
        // 1. 拿到工厂
        ShapeFactory shapeFactory = new ShapeFactory();

        // 2. 提需求:要圆形,工厂返回产品(不用自己new Circle())
        Shape circle = shapeFactory.getShape("CIRCLE");
        circle.draw(); // 用产品:画圆形

        // 3. 提需求:要矩形
        Shape rectangle = shapeFactory.getShape("RECTANGLE");
        rectangle.draw(); // 用产品:画矩形

        // 4. 提需求:要正方形
        Shape square = shapeFactory.getShape("SQUARE");
        square.draw(); // 用产品:画正方形
    }
}
运行结果
复制代码
画了一个圆形
画了一个矩形
画了一个正方形

六、工厂模式的 3 个变种

就像责任链有 "单向链、环形链",工厂模式也有 3 个核心变种,核心都是 "创建与使用分离",只是灵活度不同:

变种类型 通俗解释(类比现实) 核心特点 适用场景
简单工厂模式(入门) 一个工厂干所有活:比如 "小作坊",又造圆形又造矩形 没有抽象工厂,逻辑都在具体工厂(像责任链只有一个具体处理器) 产品类型少、变化少(比如只有 3 种形状)
工厂方法模式(进阶) 一个工厂只干一件活:"圆形工厂" 只造圆形,"矩形工厂" 只造矩形 每个具体产品对应一个具体工厂(像责任链每个处理器只处理一种请求) 产品类型多、需要扩展(比如新增三角形,只加 "三角形工厂")
抽象工厂模式(高阶) 一个工厂造 "一套产品":比如 "家电工厂" 造电视 + 冰箱,"手机工厂" 造手机 + 耳机 抽象工厂定义 "造一套产品" 的接口,具体工厂实现整套生产(像责任链处理 "一系列相关请求") 产品是 "成套出现" 的(比如数据库驱动 + 方言、UI 组件套系)

👉 重点:不管哪个变种,核心都没变 ------ 客户端只提需求,工厂负责创建,不用直接new

七、优点 & 缺点

优点
  1. 解耦:创建对象和使用对象分开,客户端不用关心 "怎么造",只关心 "怎么用"(像责任链客户端不用关心 "谁处理");
  2. 易扩展:新增产品时,简单工厂改工厂逻辑,工厂方法 / 抽象工厂只加新工厂 + 新产品,不用改客户端(像责任链加新处理器,不用改客户端);
  3. 易维护 :创建逻辑集中在工厂,要改只改工厂(比如圆形的draw()逻辑变了,只改Circle类,不用改所有客户端)。
缺点
  1. 类变多:工厂方法 / 抽象工厂模式下,一个产品对应一个工厂,类的数量会翻倍
  2. 简单场景没必要 :如果对象很简单(比如new User()就一行),用工厂模式会多一个工厂类,反而增加复杂度(像责任链处理简单请求,没必要搞链路);
  3. 扩展有局限:抽象工厂模式如果要新增 "成套产品" 中的一个(比如家电工厂原本造电视 + 冰箱,现在要加洗衣机),需要改抽象工厂接口,违反开闭原则

八、实际应用场景

工厂模式在开发中很常用,到处都是:

  1. 数据库访问:Hibernate 换数据库时,只改 "数据库工厂" 的配置(MySQL 工厂→Oracle 工厂),不用改业务代码;
  2. 日志框架:日志可以输出到硬盘、控制台、远程服务器,对应 "硬盘日志工厂""控制台日志工厂",客户端选一个就行;
  3. 框架源码 :Spring 的BeanFactory(创建 Bean 对象)、Java 的Calendar.getInstance()(创建日历对象),本质都是工厂模式;
  4. 插件开发:比如 IDE 的插件,每个插件对应一个 "插件工厂",IDE 启动时通过工厂创建插件实例。

九、注意事项

  1. 别过度设计 :简单对象直接new,复杂对象(创建要 3 行以上代码)再用工厂;
  2. 优先选简单工厂 / 工厂方法:大多数场景下,简单工厂(产品少)或工厂方法(产品多)就够了,抽象工厂除非是 "成套产品",否则不用;
  3. 避免工厂逻辑太复杂 :如果工厂里的if-else太多(比如简单工厂有 10 种产品),可以结合责任链或策略模式优化(但这是进阶操作,基础场景不用)。

总结

工厂模式的核心就是 "把创建对象的活儿交给专业的人(工厂)干",本质是 "创建与使用分离"------ 和责任链 "处理请求与发起请求分离" 的思想异曲同工。

记住:能直接new且不麻烦的,就不用工厂;创建逻辑复杂、需要灵活切换的,就用工厂。按这个原则选,永远不会错!

相关推荐
a努力。2 小时前
国家电网Java面试被问:混沌工程在分布式系统中的应用
java·开发语言·数据库·git·mysql·面试·职场和发展
Yvonne爱编码2 小时前
Java 四大内部类全解析:从设计本质到实战应用
java·开发语言·python
J2虾虾2 小时前
SpringBoot和mybatis Plus不兼容报错的问题
java·spring boot·mybatis
毕设源码-郭学长3 小时前
【开题答辩全过程】以 基于springboot 的豪华婚车租赁系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
Tao____4 小时前
通用性物联网平台
java·物联网·mqtt·低代码·开源
曹轲恒5 小时前
SpringBoot整合SpringMVC(上)
java·spring boot·spring
JH30735 小时前
Java Spring中@AllArgsConstructor注解引发的依赖注入异常解决
java·开发语言·spring
码农水水6 小时前
米哈游Java面试被问:机器学习模型的在线服务和A/B测试
java·开发语言·数据库·spring boot·后端·机器学习·word
2601_949575866 小时前
Flutter for OpenHarmony二手物品置换App实战 - 表单验证实现
android·java·flutter