工厂模式

tim-qtp...大约 6 分钟设计模式

工厂模式的核心思想是我不直接创建对象,而是让一个专门的‘工厂’帮我创建对象。”**这样做的好处是代码更加灵活,扩展性更强,而且可以隐藏对象的创建细节。

工厂模式的核心概念

  1. 客户端(Client):需要使用对象的地方。
  2. 工厂(Factory):负责创建对象的地方。
  3. 产品(Product):被创建的对象。

工厂模式的类型

工厂模式有几种变体,比如简单工厂模式工厂方法模式抽象工厂模式。我们先从最简单的开始讲起。


1. 简单工厂模式

场景

假设你开了一家冰淇淋店,顾客可以点不同口味的冰淇淋。如果你直接在代码中写:

if (flavor.equals("vanilla")) {
    return new VanillaIceCream();
} else if (flavor.equals("chocolate")) {
    return new ChocolateIceCream();
}

这样代码会很混乱,而且每次新增口味都要修改代码。这时候就可以用简单工厂模式。

实现代码

// 产品接口:冰淇淋
interface IceCream {
    void eat();
}

// 具体产品:香草冰淇淋
class VanillaIceCream implements IceCream {
    @Override
    public void eat() {
        System.out.println("吃了一碗香草冰淇淋!");
    }
}

// 具体产品:巧克力冰淇淋
class ChocolateIceCream implements IceCream {
    @Override
    public void eat() {
        System.out.println("吃了一碗巧克力冰淇淋!");
    }
}

// 工厂类:冰淇淋工厂
class IceCreamFactory {
    public static IceCream createIceCream(String flavor) {
        if (flavor == null) {
            return null;
        }
        if (flavor.equalsIgnoreCase("vanilla")) {
            return new VanillaIceCream();
        } else if (flavor.equalsIgnoreCase("chocolate")) {
            return new ChocolateIceCream();
        } else {
            return null;
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 客户端不需要直接创建对象,而是通过工厂获取
        IceCream iceCream = IceCreamFactory.createIceCream("vanilla");
        iceCream.eat(); // 输出:吃了一碗香草冰淇淋!

        IceCream anotherIceCream = IceCreamFactory.createIceCream("chocolate");
        anotherIceCream.eat(); // 输出:吃了一碗巧克力冰淇淋!
    }
}

大白话解释

  • 产品:冰淇淋,有香草味和巧克力味。
  • 工厂:冰淇淋工厂,负责根据顾客的需求(香草味或巧克力味)创建对应的冰淇淋。
  • 客户端:顾客,只需要告诉工厂要什么口味,工厂会帮你准备好。

好处:如果未来要增加草莓味冰淇淋,只需要在工厂里加一个分支:

else if (flavor.equalsIgnoreCase("strawberry")) {
    return new StrawberryIceCream();
}

不需要修改客户端代码。


2. 工厂方法模式

场景

简单工厂模式看起来很好,但如果冰淇淋的种类越来越多,工厂类会变得很臃肿(很多 if-else)。工厂方法模式则把创建对象的逻辑分散到不同的子类中。

实现代码

// 产品接口:冰淇淋
interface IceCream {
    void eat();
}

// 具体产品:香草冰淇淋
class VanillaIceCream implements IceCream {
    @Override
    public void eat() {
        System.out.println("吃了一碗香草冰淇淋!");
    }
}

// 具体产品:巧克力冰淇淋
class ChocolateIceCream implements IceCream {
    @Override
    public void eat() {
        System.out.println("吃了一碗巧克力冰淇淋!");
    }
}

// 工厂接口:冰淇淋工厂
interface IceCreamFactory {
    IceCream createIceCream();
}

// 具体工厂:香草冰淇淋工厂
class VanillaIceCreamFactory implements IceCreamFactory {
    @Override
    public IceCream createIceCream() {
        return new VanillaIceCream();
    }
}

// 具体工厂:巧克力冰淇淋工厂
class ChocolateIceCreamFactory implements IceCreamFactory {
    @Override
    public IceCream createIceCream() {
        return new ChocolateIceCream();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 客户端通过具体的工厂来创建对象
        IceCreamFactory vanillaFactory = new VanillaIceCreamFactory();
        IceCream vanillaIceCream = vanillaFactory.createIceCream();
        vanillaIceCream.eat(); // 输出:吃了一碗香草冰淇淋!

        IceCreamFactory chocolateFactory = new ChocolateIceCreamFactory();
        IceCream chocolateIceCream = chocolateFactory.createIceCream();
        chocolateIceCream.eat(); // 输出:吃了一碗巧克力冰淇淋!
    }
}

大白话解释

  • 工厂接口:冰淇淋工厂的通用接口,定义了“创建冰淇淋”的方法。
  • 具体工厂:每个口味的冰淇淋都有自己的工厂(香草工厂、巧克力工厂)。每个工厂只负责创建一种冰淇淋。
  • 客户端:顾客只需要选择一个工厂(比如香草工厂),工厂会自动帮你创建对应的冰淇淋。

好处:如果新增草莓冰淇淋,只需要新增一个 StrawberryIceCream 类和一个 StrawberryIceCreamFactory 类,不需要修改现有代码。这样代码的扩展性更好。


3. 抽象工厂模式

场景

假设你的冰淇淋店不仅卖冰淇淋,还卖冰沙。简单工厂和工厂方法模式只能创建同一种类型的产品(比如只创建冰淇淋)。抽象工厂模式则可以同时创建多种相关的产品(比如同时创建冰淇淋和冰沙)。

实现代码

// 冰淇淋接口
interface IceCream {
    void eat();
}

// 香草冰淇淋
class VanillaIceCream implements IceCream {
    @Override
    public void eat() {
        System.out.println("吃了一碗香草冰淇淋!");
    }
}

// 巧克力冰淇淋
class ChocolateIceCream implements IceCream {
    @Override
    public void eat() {
        System.out.println("吃了一碗巧克力冰淇淋!");
    }
}

// 冰沙接口
interface Slush {
    void drink();
}

// 香草冰沙
class VanillaSlush implements Slush {
    @Override
    public void drink() {
        System.out.println("喝了一杯香草冰沙!");
    }
}

// 巧克力冰沙
class ChocolateSlush implements Slush {
    @Override
    public void drink() {
        System.out.println("喝了一杯巧克力冰沙!");
    }
}

// 抽象工厂接口
interface DessertFactory {
    IceCream createIceCream();
    Slush createSlush();
}

// 香草工厂
class VanillaFactory implements DessertFactory {
    @Override
    public IceCream createIceCream() {
        return new VanillaIceCream();
    }

    @Override
    public Slush createSlush() {
        return new VanillaSlush();
    }
}

// 巧克力工厂
class ChocolateFactory implements DessentFactory {
    @Override
    public IceCream createIceCream() {
        return new ChocolateIceCream();
    }

    @Override
    public Slush createSlush() {
        return new ChocolateSlush();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 选择香草工厂
        DessertFactory vanillaFactory = new VanillaFactory();
        IceCream vanillaIceCream = vanillaFactory.createIceCream();
        Slush vanillaSlush = vanillaFactory.createSlush();
        vanillaIceCream.eat(); // 输出:吃了一碗香草冰淇淋!
        vanillaSlush.drink();  // 输出:喝了一杯香草冰沙!

        // 选择巧克力工厂
        DessertFactory chocolateFactory = new ChocolateFactory();
        IceCream chocolateIceCream = chocolateFactory.createIceCream();
        Slush chocolateSlush = chocolateFactory.createSlush();
        chocolateIceCream.eat(); // 输出:吃了一碗巧克力冰淇淋!
        chocolateSlush.drink();  // 输出:喝了一杯巧克力冰沙!
    }
}

大白话解释

  • 产品族:冰淇淋和冰沙是一对相关的产品,香草工厂可以同时生产香草冰淇淋和香草冰沙,巧克力工厂可以同时生产巧克力冰淇淋和巧克力冰沙。
  • 抽象工厂接口:定义了“创建冰淇淋”和“创建冰沙”的方法。
  • 具体工厂:每个工厂(香草工厂、巧克力工厂)都可以创建一组相关的产品。
  • 客户端:顾客只需要选择一个工厂,就可以同时获得冰淇淋和冰沙。

好处:如果新增草莓口味,只需要新增一个草莓工厂,而不需要修改现有代码。同时,抽象工厂模式可以创建一组相关的产品,而不是单一的产品。


总结

  1. 简单工厂模式:用一个工厂类来创建对象,但扩展性较差(太多 if-else)。
  2. 工厂方法模式:用多个工厂类

4. 实际java开发中,有哪些常用的工厂模式呢

1. Spring 框架

  • BeanFactoryApplicationContext:Spring 的核心功能之一,通过配置(注解或XML)动态创建和管理Bean。客户端代码通过工厂获取Bean实例,而无需关心具体的创建细节。

2. JDBC 的 DriverManager

  • 数据库连接工厂DriverManager 根据数据库URL、用户名和密码,动态创建数据库连接(Connection)。客户端代码只需要调用 DriverManager.getConnection(),而无需直接管理连接的创建过程。