设计模式(工厂模式)

发布于:2025-05-01 ⋅ 阅读:(21) ⋅ 点赞:(0)

工厂设计模式:打造你的代码生产线

引言

想象一下,你正站在一家现代化的玩具工厂门前。工厂内部,各种机器有条不紊地运转,原材料在传送带上流动,最终变成精美的玩具。你不需要了解每个玩具的具体制作工艺,只需告诉工厂经理:“我需要一个泰迪熊”,工厂就会为你生产出来。这正是工厂设计模式的核心思想 — 封装对象的创建过程,使客户端代码与具体产品的实现细节解耦

在这里插入图片描述

什么是工厂设计模式?

工厂设计模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,而是通过使用一个共同的接口来指向新创建的对象。

工厂模式主要分为三种类型:

  1. 简单工厂模式(Simple Factory)
  2. 工厂方法模式(Factory Method)
  3. 抽象工厂模式(Abstract Factory)

简单工厂模式:披萨店的点单系统

场景描述

想象你走进了一家披萨店。你不需要自己准备面团、酱料和配料,只需告诉服务员你想要什么类型的披萨(如"奶酪披萨"、“素食披萨"或"肉食披萨”),服务员就会将你的订单传递给厨房,厨房(工厂)将为你制作披萨。

在这里插入图片描述

代码实现

// 披萨接口
interface Pizza {
    void prepare();
    void bake();
    void cut();
    void box();
}

// 具体披萨类 - 奶酪披萨
class CheesePizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("准备奶酪披萨的原料...");
    }

    @Override
    public void bake() {
        System.out.println("烘烤奶酪披萨...");
    }

    @Override
    public void cut() {
        System.out.println("切割奶酪披萨...");
    }

    @Override
    public void box() {
        System.out.println("包装奶酪披萨...");
    }
}

// 具体披萨类 - 素食披萨
class VeggiePizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("准备素食披萨的原料...");
    }

    @Override
    public void bake() {
        System.out.println("烘烤素食披萨...");
    }

    @Override
    public void cut() {
        System.out.println("切割素食披萨...");
    }

    @Override
    public void box() {
        System.out.println("包装素食披萨...");
    }
}

// 简单工厂
class SimplePizzaFactory {
    public Pizza createPizza(String type) {
        Pizza pizza = null;

        if (type.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (type.equals("veggie")) {
            pizza = new VeggiePizza();
        }
        // 可以添加更多披萨类型...

        return pizza;
    }
}

// 披萨店类
class PizzaStore {
    private SimplePizzaFactory factory;

    public PizzaStore(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    public Pizza orderPizza(String type) {
        Pizza pizza = factory.createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}

// 客户端代码
public class SimplePizzaExample {
    public static void main(String[] args) {
        SimplePizzaFactory factory = new SimplePizzaFactory();
        PizzaStore store = new PizzaStore(factory);
        
        // 订购奶酪披萨
        Pizza cheesePizza = store.orderPizza("cheese");
        System.out.println("小明订购了一个奶酪披萨\n");
        
        // 订购素食披萨
        Pizza veggiePizza = store.orderPizza("veggie");
        System.out.println("小红订购了一个素食披萨");
    }
}

简单工厂模式的优缺点

优点:

  • 客户端不需要知道具体产品类的类名,只需知道对应的参数即可
  • 将创建实例的过程与使用实例的过程分离,使用者不必关心创建的细节

缺点:

  • 工厂类集中了所有产品的创建逻辑,一旦工厂类出现问题,整个系统都会受到影响
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,违反了开闭原则

工厂方法模式:特色地区披萨店连锁

场景描述

随着业务扩展,披萨店开始在不同城市开设分店。每个地区的分店都有自己的特色披萨。比如,纽约店的披萨饼皮薄而脆,而芝加哥店的披萨饼皮厚实松软。这时候,简单工厂已经不能满足需求,需要让各个分店能够创建自己特色的披萨。
在这里插入图片描述

代码实现

// 披萨接口
interface Pizza {
    void prepare();
    void bake();
    void cut();
    void box();
    String getName();
}

// 纽约风格奶酪披萨
class NYStyleCheesePizza implements Pizza {
    private String name = "纽约风格奶酪披萨";

    @Override
    public void prepare() {
        System.out.println("准备 " + name);
    }

    @Override
    public void bake() {
        System.out.println("烘烤25分钟");
    }

    @Override
    public void cut() {
        System.out.println("对角线切片");
    }

    @Override
    public void box() {
        System.out.println("放入纽约披萨店盒子中");
    }

    @Override
    public String getName() {
        return name;
    }
}

// 芝加哥风格奶酪披萨
class ChicagoStyleCheesePizza implements Pizza {
    private String name = "芝加哥风格深盘奶酪披萨";

    @Override
    public void prepare() {
        System.out.println("准备 " + name);
    }

    @Override
    public void bake() {
        System.out.println("烘烤40分钟");
    }

    @Override
    public void cut() {
        System.out.println("方块切片");
    }

    @Override
    public void box() {
        System.out.println("放入芝加哥披萨店盒子中");
    }

    @Override
    public String getName() {
        return name;
    }
}

// 抽象披萨店
abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);
        
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        
        return pizza;
    }
    
    // 工厂方法
    protected abstract Pizza createPizza(String type);
}

// 纽约披萨店
class NYPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new NYStyleCheesePizza();
        }
        // 可以添加更多纽约风格披萨...
        return null;
    }
}

// 芝加哥披萨店
class ChicagoPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new ChicagoStyleCheesePizza();
        }
        // 可以添加更多芝加哥风格披萨...
        return null;
    }
}

// 客户端代码
public class FactoryMethodExample {
    public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();
        
        Pizza pizza = nyStore.orderPizza("cheese");
        System.out.println("小明订购了 " + pizza.getName() + "\n");
        
        pizza = chicagoStore.orderPizza("cheese");
        System.out.println("小红订购了 " + pizza.getName());
    }
}

工厂方法模式的优缺点

优点:

  • 符合开闭原则,新增产品时,只需添加具体工厂和产品类,不需要修改原有代码
  • 符合单一职责原则,每个具体工厂只负责创建对应的产品
  • 客户端只需要知道产品的抽象类,无须关心具体实现类

缺点:

  • 类的个数容易过多,增加复杂度
  • 增加了系统的抽象性和理解难度

抽象工厂模式:披萨原料工厂

场景描述

随着披萨连锁店的成功,管理层决定统一原料供应链,确保每家分店都使用高质量的原料。不同地区的披萨店需要使用不同风格的原料(如纽约的薄面团和马苏里拉奶酪,芝加哥的厚面团和意大利白干酪)。

在这里插入图片描述

代码实现

// 原料接口
interface Dough {
    String toString();
}

interface Sauce {
    String toString();
}

interface Cheese {
    String toString();
}

// 具体原料类
class ThinCrustDough implements Dough {
    public String toString() {
        return "薄饼皮";
    }
}

class ThickCrustDough implements Dough {
    public String toString() {
        return "厚饼皮";
    }
}

class MarinaraSauce implements Sauce {
    public String toString() {
        return "番茄酱";
    }
}

class PlumTomatoSauce implements Sauce {
    public String toString() {
        return "李子番茄酱";
    }
}

class MozzarellaCheese implements Cheese {
    public String toString() {
        return "马苏里拉奶酪";
    }
}

class ReggianoCheese implements Cheese {
    public String toString() {
        return "雷吉亚诺奶酪";
    }
}

// 抽象原料工厂
interface PizzaIngredientFactory {
    Dough createDough();
    Sauce createSauce();
    Cheese createCheese();
    // 可以添加更多原料...
}

// 具体原料工厂 - 纽约
class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }

    @Override
    public Sauce createSauce() {
        return new MarinaraSauce();
    }

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }
}

// 具体原料工厂 - 芝加哥
class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {
    @Override
    public Dough createDough() {
        return new ThickCrustDough();
    }

    @Override
    public Sauce createSauce() {
        return new PlumTomatoSauce();
    }

    @Override
    public Cheese createCheese() {
        return new MozzarellaCheese();
    }
}

// 抽象产品 - 披萨
abstract class Pizza {
    String name;
    Dough dough;
    Sauce sauce;
    Cheese cheese;
    
    abstract void prepare();
    
    void bake() {
        System.out.println("烘烤175度,25分钟");
    }
    
    void cut() {
        System.out.println("将披萨对角切片");
    }
    
    void box() {
        System.out.println("将披萨放在官方盒子里");
    }
    
    void setName(String name) {
        this.name = name;
    }
    
    String getName() {
        return name;
    }
    
    public String toString() {
        StringBuilder result = new StringBuilder();
        result.append("---- ").append(name).append(" ----\n");
        if (dough != null) {
            result.append(dough).append("\n");
        }
        if (sauce != null) {
            result.append(sauce).append("\n");
        }
        if (cheese != null) {
            result.append(cheese);
        }
        return result.toString();
    }
}

// 具体产品 - 奶酪披萨
class CheesePizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;
    
    public CheesePizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }
    
    @Override
    void prepare() {
        System.out.println("准备 " + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
    }
}

// 改进后的披萨店
abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);
        
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        
        return pizza;
    }
    
    protected abstract Pizza createPizza(String type);
}

// 纽约披萨店
class NYPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        
        if (type.equals("cheese")) {
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("纽约风格奶酪披萨");
        }
        // 可以添加更多纽约风格披萨...
        
        return pizza;
    }
}

// 芝加哥披萨店
class ChicagoPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory();
        
        if (type.equals("cheese")) {
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("芝加哥风格奶酪披萨");
        }
        // 可以添加更多芝加哥风格披萨...
        
        return pizza;
    }
}

// 客户端代码
public class AbstractFactoryExample {
    public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();
        
        Pizza pizza = nyStore.orderPizza("cheese");
        System.out.println("小明订购了:\n" + pizza + "\n");
        
        pizza = chicagoStore.orderPizza("cheese");
        System.out.println("小红订购了:\n" + pizza);
    }
}

抽象工厂模式的优缺点

优点:

  • 产品族的约束性,确保一系列相关的产品对象被一起创建
  • 将一个系列的产品族统一到一起创建,减少了具体产品对象的依赖
  • 符合开闭原则,易于扩展,可以在不修改已有代码的情况下引入新的产品族

缺点:

  • 扩展产品族比较困难,需要修改抽象工厂的接口
  • 比工厂方法模式更加抽象,更难理解

工厂模式在实际开发中的应用

工厂模式在许多框架和应用中被广泛使用:

  1. Java集合框架Collections.singleton()Collections.singletonList()等方法都是工厂方法的实现。

  2. JDBC连接数据库:通过DriverManager.getConnection()方法获取数据库连接对象,隐藏了具体数据库连接的细节。

  3. Spring框架:Spring的BeanFactory是工厂模式的典型应用,它根据配置文件创建不同的Bean对象。

  4. 日志框架:如Log4j、SLF4J等,它们使用工厂模式创建不同的日志对象。

总结

工厂设计模式是一种非常实用的创建型设计模式,它通过封装对象的创建过程,使客户端代码与具体产品的实现细节解耦。根据不同的需求和场景,我们可以选择使用简单工厂、工厂方法或抽象工厂。

  • 简单工厂:适用于产品种类相对固定,变化不大的场景。
  • 工厂方法:适用于产品种类多样化,需要不同工厂创建不同产品的场景。
  • 抽象工厂:适用于需要创建一系列相关或依赖对象的场景,无须指定它们的具体类。

网站公告

今日签到

点亮在社区的每一天
去签到