【从零入门23种设计模式01】创建型之工厂模式(简单工厂+工厂方法+抽象工厂)

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一,它提供了一种创建对象的方式,使得创建对象的过程(也许复杂)与使用对象的过程分离。

一、工厂模式核心思想

工厂模式的核心是将对象的创建过程封装起来,把对象创建和使用分离。就像现实中你想买手机,不需要自己造(不用关心 "创建过程"),只需要去手机工厂(工厂类)下单,工厂会直接给你成品(对象)。

这种模式的核心价值:

  • 降低代码耦合:使用方无需知道对象的具体创建逻辑(比如类的构造参数、初始化步骤);
  • 提高扩展性:新增产品时,只需扩展工厂类,无需修改原有使用代码;
  • 提高可读性:统一的工厂入口让对象创建逻辑更清晰。

工厂模式主要分为三类(由简单到复杂):

  1. 简单工厂模式(静态工厂Simple Factory):非 GOF 标准设计模式,但最常用;
  2. 工厂方法模式(Factory Method):GOF 标准设计模式,解决简单工厂的 "开闭原则" 问题;
  3. 抽象工厂模式(Abstract Factory):GOF 标准设计模式,用于创建一组相关 / 依赖的对象。

下面举个生动例子助你理解:

(1)若没有工厂,客户需要一款苹果,那么就需要客户自己去创建一款苹果(比如自己培育、采摘、清洗),然后拿来吃。

(2)简单工厂模式:后来出现了水果工厂,用户不再需要自己动手创建苹果,由水果工厂统一负责创建,想要什么水果,直接告诉工厂就行。比如想要苹果,工厂就创建苹果;想要香蕉,工厂就创建香蕉。

(3)工厂方法模式:为了满足客户多样化的需求,水果的品类越来越多,如红富士苹果、青苹果、小米蕉、帝王蕉等等,一个水果工厂无法兼顾所有品类的生产,于是拆分出多个具体的水果工厂,每个具体工厂只生产一种品类 ------ 红富士工厂只生产红富士苹果,青苹果工厂只生产青苹果,小米蕉工厂只生产小米蕉。而 "水果工厂" 本身变成了一个抽象的规范,你需要指定具体的工厂(比如 "我要红富士工厂的产品"),才能拿到对应的水果。

(4)抽象工厂模式:随着客户要求越来越高,买水果时还需要配套的工具(比如苹果配削皮刀、香蕉配切块刀),于是这些工厂不再只生产水果,而是生产 "水果 + 配套工具" 的组合套装。最终客户只要对水果工厂的店员说:"我要红富士苹果 + 不锈钢削皮刀套餐",店员就直接从对应的抽象工厂里拿出红富士苹果和配套的削皮刀,客户不用自己去准备苹果和削皮刀,也不用操心两者是否适配。

二、简单工厂模式

代码实现:

核心逻辑:一个工厂类(通常含静态方法)根据传入的参数,创建不同类型的产品对象,使用方只需调用工厂方法并传入参数即可。

场景示例:创建不同类型的 "水果" 对象(苹果、香蕉)。

复制代码
// 第一步:定义产品接口(统一的产品规范)
interface Fruit {
    void getName(); // 产品的统一行为
}

// 第二步:实现具体产品类
class Apple implements Fruit {
    @Override
    public void getName() {
        System.out.println("我是苹果");
    }
}

class Banana implements Fruit {
    @Override
    public void getName() {
        System.out.println("我是香蕉");
    }
}

// 第三步:创建简单工厂类(核心:封装创建逻辑)
class FruitFactory {
    // 静态工厂方法:根据参数创建不同产品
    public static Fruit createFruit(String type) {
        switch (type) {
            case "apple":
                return new Apple();
            case "banana":
                return new Banana();
            default:
                throw new IllegalArgumentException("不支持的水果类型:" + type);
        }
    }
}

// 测试使用
public class SimpleFactoryTest {
    public static void main(String[] args) {
        // 使用方无需new Apple()/new Banana(),只需调用工厂方法
        Fruit apple = FruitFactory.createFruit("apple");
        apple.getName(); // 输出:我是苹果

        Fruit banana = FruitFactory.createFruit("banana");
        banana.getName(); // 输出:我是香蕉
    }
}

简单工厂模式的优缺点:

  • 优点:简单工厂模式的优点在于将对象创建逻辑封装到单一工厂类中,使用方无需关注产品的具体创建细节,只需传入参数即可获取对应产品,大幅简化了对象调用流程、降低了代码耦合度;
  • 缺点:但缺点也十分明显,该模式违反 "开闭原则",新增产品时必须修改工厂类的核心逻辑(如 switch/case 分支------ 新增水果(比如橙子)时,需要修改FruitFactoryswitch逻辑),易引发代码风险,且所有产品的创建逻辑集中在一个工厂类中,会导致工厂类职责过重,难以维护,尤其不适用于产品类型频繁扩展的场景。

为了解决简单工厂模式的问题,便设计了工厂方法模式。

三、工厂方法模式

代码实现:

核心逻辑:将 "创建具体产品" 的逻辑从单一工厂类拆分为多个 "工厂子类",每个工厂子类只负责创建一种产品。新增产品时,只需新增 "产品类 + 工厂子类",无需修改原有代码,符合 "开闭原则"。

场景示例:基于上面的水果场景,改造为工厂方法模式。

复制代码
// 第一步:定义产品接口(和简单工厂一致)
interface Fruit {
    void getName();
}

// 第二步:实现具体产品类(和简单工厂一致)
class Apple implements Fruit {
    @Override
    public void getName() {
        System.out.println("我是苹果");
    }
}

class Banana implements Fruit {
    @Override
    public void getName() {
        System.out.println("我是香蕉");
    }
}

// 第三步:定义工厂接口(统一的工厂规范)
interface FruitFactory {
    Fruit createFruit(); // 工厂的统一创建方法
}

// 第四步:实现具体工厂类(每个工厂对应一种产品)
class AppleFactory implements FruitFactory {
    @Override
    public Fruit createFruit() {
        return new Apple(); // 只创建苹果
    }
}

class BananaFactory implements FruitFactory {
    @Override
    public Fruit createFruit() {
        return new Banana(); // 只创建香蕉
    }
}

// 测试使用
public class FactoryMethodTest {
    public static void main(String[] args) {
        // 创建苹果:先创建苹果工厂,再生产苹果
        FruitFactory appleFactory = new AppleFactory();
        Fruit apple = appleFactory.createFruit();
        apple.getName(); // 输出:我是苹果

        // 创建香蕉:先创建香蕉工厂,再生产香蕉
        FruitFactory bananaFactory = new BananaFactory();
        Fruit banana = bananaFactory.createFruit();
        banana.getName(); // 输出:我是香蕉
    }
}

工厂方法模式的优缺点:

  • 优点:符合 "开闭原则",新增橙子只需加Orange类 +OrangeFactory类,原有代码无需修改;
  • 缺点:类数量膨胀 ------ 每新增一个产品,就要新增一个产品类 + 一个工厂类。

四、 抽象工厂模式

抽象工厂模式包含以下几个主要角色:

  • 抽象工厂(Abstract Factory):声明了一组用于创建产品对象的方法,每个方法对应一种产品类型。抽象工厂可以是接口或抽象类。
  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体产品对象的实例。
  • 抽象产品(Abstract Product):定义了一组产品对象的共同接口或抽象类,描述了产品对象的公共方法。
  • 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。

产品等级结构:

产品等级结构指的是产品的继承结构,例如一个水果抽象类,它有苹果、香蕉、橙子等一系列的子类,而苹果子类又细分出红富士苹果、青苹果、阿克苏苹果等子子类,那么这个水果抽象类和它的所有子类(苹果、香蕉、橙子等)就构成了一个产品等级结构;同理,一个水果工具抽象类,它有削皮刀、切块刀、去核器等一系列子类,这个水果工具抽象类和它的子类也构成了一个独立的产品等级结构。

产品族:

产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。比如,红富士专属工厂生产红富士苹果(属于 "水果" 产品等级结构)、红富士苹果专用削皮刀(属于 "水果工具" 产品等级结构),那么红富士苹果和红富士苹果专用削皮刀就属于红富士工厂对应的产品族;再比如,香蕉工厂生产小米蕉(属于 "水果" 产品等级结构)、香蕉专用切块刀(属于 "水果工具" 产品等级结构),那么小米蕉和香蕉专用切块刀就属于香蕉工厂对应的产品族。

代码实现:

核心逻辑:用于创建 "一组相关 / 依赖的产品"(比如 "手机 + 充电器"、"宝马汽车 + 宝马配件"),工厂类负责创建这一组产品,而非单一产品。

场景示例:创建 "手机 + 充电器" 的产品组合(华为系列、小米系列)。

复制代码
// 第一步:定义第一组产品接口(手机)
interface Phone {
    void getBrand();
}

// 第二步:定义第二组产品接口(充电器)
interface Charger {
    void matchPhone();
}

// 第三步:实现具体产品(华为手机+华为充电器)
class HuaweiPhone implements Phone {
    @Override
    public void getBrand() {
        System.out.println("华为手机");
    }
}

class HuaweiCharger implements Charger {
    @Override
    public void matchPhone() {
        System.out.println("华为充电器,适配华为手机");
    }
}

// 第四步:实现具体产品(小米手机+小米充电器)
class XiaomiPhone implements Phone {
    @Override
    public void getBrand() {
        System.out.println("小米手机");
    }
}

class XiaomiCharger implements Charger {
    @Override
    public void matchPhone() {
        System.out.println("小米充电器,适配小米手机");
    }
}

// 第五步:定义抽象工厂接口(创建一组产品的规范)
interface ElectronicFactory {
    Phone createPhone(); // 创建手机
    Charger createCharger(); // 创建充电器
}

// 第六步:实现具体工厂(华为工厂:生产华为手机+充电器)
class HuaweiFactory implements ElectronicFactory {
    @Override
    public Phone createPhone() {
        return new HuaweiPhone();
    }

    @Override
    public Charger createCharger() {
        return new HuaweiCharger();
    }
}

// 小米工厂:生产小米手机+充电器
class XiaomiFactory implements ElectronicFactory {
    @Override
    public Phone createPhone() {
        return new XiaomiPhone();
    }

    @Override
    public Charger createCharger() {
        return new XiaomiCharger();
    }
}

// 测试使用
public class AbstractFactoryTest {
    public static void main(String[] args) {
        // 创建华为产品组合
        ElectronicFactory huaweiFactory = new HuaweiFactory();
        Phone huaweiPhone = huaweiFactory.createPhone();
        Charger huaweiCharger = huaweiFactory.createCharger();
        huaweiPhone.getBrand(); // 输出:华为手机
        huaweiCharger.matchPhone(); // 输出:华为充电器,适配华为手机

        // 创建小米产品组合
        ElectronicFactory xiaomiFactory = new XiaomiFactory();
        Phone xiaomiPhone = xiaomiFactory.createPhone();
        Charger xiaomiCharger = xiaomiFactory.createCharger();
        xiaomiPhone.getBrand(); // 输出:小米手机
        xiaomiCharger.matchPhone(); // 输出:小米充电器,适配小米手机
    }
}

抽象工厂模式的优缺点:

  • 优点:能保证 "一组产品" 的兼容性(比如华为充电器一定适配华为手机);
  • 缺点:扩展性差 ------ 如果要新增产品(比如耳机),需要修改抽象工厂接口和所有具体工厂类,违反 "开闭原则"。

五、工厂模式的实际应用场景

  • JDK 中的应用
    • java.util.Calendar.getInstance():静态工厂模式,根据时区 / 地区创建不同的 Calendar 实例;
    • java.sql.DriverManager.getConnection():简单工厂模式,根据 URL 创建不同数据库的 Connection;
  • 框架中的应用
    • Spring 的BeanFactory:工厂模式的典型应用,负责创建和管理 Bean 对象;
    • MyBatis 的SqlSessionFactory:工厂方法模式,创建 SqlSession 对象。
  • 核心价值 :工厂模式的核心是分离对象的 "创建" 和 "使用",降低耦合、提高扩展性;
  • 选型建议
    • 简单场景(产品类型少、变动少):用简单工厂模式;
    • 产品类型多、需要频繁扩展:用工厂方法模式;
    • 需要创建一组相关产品:用抽象工厂模式;
  • 核心原则:工厂模式的设计始终围绕 "开闭原则"------ 新增功能时,优先扩展类,而非修改原有类
相关推荐
重生之后端学习1 小时前
208. 实现 Trie (前缀树)
java·开发语言·数据结构·算法·职场和发展·深度优先
Sayuanni%31 小时前
初阶_多线程2(线程安全)
java
Howie Zphile1 小时前
# 组织增熵与全面预算管理的持续优化
java·大数据·数据库
芒克芒克1 小时前
深入浅出BlockingQueue(二)
java
识君啊1 小时前
Java 栈 - 附LeetCode 经典题解
java·数据结构·leetcode·deque··stack·lifo
shehuiyuelaiyuehao2 小时前
关于hashset和hashmap,还有treeset和treemap,四个的关系
java·开发语言
马尔代夫哈哈哈2 小时前
Spring AOP
java·后端·spring
only-qi2 小时前
Java 包装器模式:告别“类爆炸“
java·开发语言
Yweir2 小时前
Java 接口测试框架 Restassured
java·开发语言