设计模式-工厂模式:解耦对象创建的设计艺术

工厂模式详解:从制鞋厂看对象创建的艺术

如果把编程比作生产产品,那对象创建就像工厂生产商品。想象一下:如果一家鞋厂没有生产线规划,工人想到什么鞋就做什么鞋,原材料随意堆放,客户要一双运动鞋却给了皮鞋------这样的工厂注定混乱低效。

编程中直接用 new 关键字创建对象,就像这家混乱的鞋厂。而工厂模式,就是给鞋厂设计标准化生产线的"管理体系"。本文将通过"制鞋厂"的现实场景,通俗讲解简单工厂、工厂方法、抽象工厂三种模式的原理与应用。

一、为什么需要"工厂"?------从手工制鞋到标准化生产

假设你是一家小型鞋厂老板,一开始只有两种产品:运动鞋和皮鞋。工人直接手工制作,流程如下(对应代码直接 new 对象):

java 复制代码
// 手工制鞋:客户要什么鞋,直接手工做
public class ShoeStore {
    public Shoe sellShoe(String type) {
        Shoe shoe;
        // 客户要运动鞋,就手工做一双
        if ("sports".equals(type)) {
            shoe = new SportsShoe();
            shoe.prepare(); // 准备材料:橡胶底、透气网布
            shoe.make();    // 制作:缝合、定型
        }
        // 客户要皮鞋,再手工做一双
        else if ("leather".equals(type)) {
            shoe = new LeatherShoe();
            shoe.prepare(); // 准备材料:牛皮、橡胶底
            shoe.make();    // 制作:裁剪、缝制
        }
        else {
            throw new RuntimeException("不生产这种鞋");
        }
        return shoe;
    }
}

随着订单增多,问题逐渐暴露:

  1. 工人太累 :鞋店(ShoeStore)既要接待客户,又要负责做鞋,违背"专人专事"(单一职责原则)。
  2. 扩展困难 :想新增"凉鞋"时,要修改鞋店的制作流程(sellShoe 方法),可能影响已有鞋类的生产(违背开闭原则)。
  3. 质量不稳定:不同工人做的同一款鞋工艺不一,比如运动鞋的橡胶底厚度不统一。

解决办法很简单:建一条标准化生产线(工厂) ,专门负责做鞋,鞋店只负责卖鞋。这就是工厂模式的核心思想------将"做鞋(创建对象)"和"卖鞋(使用对象)"分离

二、简单工厂:小型制鞋流水线

场景模拟

你的鞋厂规模扩大,决定建一条流水线(简单工厂),专门负责生产运动鞋和皮鞋。流水线根据订单类型(参数)决定生产哪种鞋,工人只需按流程操作。

模式定义

简单工厂是一个集中化的生产车间,通过接收"产品类型"参数,决定生产哪种产品。客户端只需告诉工厂"要什么",无需知道"怎么做"。

代码实现(制鞋场景)

java 复制代码
// 1. 抽象产品:鞋子(定义所有鞋的通用属性)
public abstract class Shoe {
    protected String name; // 鞋名
    protected String sole; // 鞋底材料
    protected String upper; // 鞋面材料
    
    // 抽象方法:准备材料(不同鞋材料不同)
    public abstract void prepare();
    
    // 通用方法:制作(所有鞋制作流程类似)
    public void make() {
        System.out.println("制作" + name + ":缝合鞋底与鞋面");
    }
    
    // 通用方法:包装
    public void box() {
        System.out.println("将" + name + "装入包装盒");
    }
}

// 2. 具体产品:运动鞋
public class SportsShoe extends Shoe {
    public SportsShoe() {
        name = "运动鞋";
    }
    
    @Override
    public void prepare() {
        sole = "橡胶底(防滑)";
        upper = "透气网布";
        System.out.println("准备" + name + "材料:" + sole + "、" + upper);
    }
}

// 2. 具体产品:皮鞋
public class LeatherShoe extends Shoe {
    public LeatherShoe() {
        name = "皮鞋";
    }
    
    @Override
    public void prepare() {
        sole = "橡胶底(耐磨)";
        upper = "牛皮";
        System.out.println("准备" + name + "材料:" + sole + "、" + upper);
    }
}

// 3. 简单工厂:制鞋流水线
public class ShoeFactory {
    // 根据订单类型生产鞋子
    public static Shoe createShoe(String type) {
        Shoe shoe = null;
        if ("sports".equals(type)) {
            shoe = new SportsShoe();
        } else if ("leather".equals(type)) {
            shoe = new LeatherShoe();
        } else {
            throw new RuntimeException("不生产" + type + "类型的鞋");
        }
        // 工厂统一完成制作流程(准备→制作→包装)
        shoe.prepare();
        shoe.make();
        shoe.box();
        return shoe;
    }
}

// 4. 客户端:鞋店(只负责卖鞋,不关心制作)
public class ShoeStore {
    public Shoe sellShoe(String type) {
        System.out.println("客户下单:" + type + "鞋");
        // 直接从工厂拿货,无需自己做
        Shoe shoe = ShoeFactory.createShoe(type);
        System.out.println("客户取走" + shoe.name + "\n");
        return shoe;
    }
    
    public static void main(String[] args) {
        ShoeStore store = new ShoeStore();
        store.sellShoe("sports"); // 卖运动鞋
        store.sellShoe("leather"); // 卖皮鞋
    }
}

运行结果

复制代码
客户下单:sports鞋
准备运动鞋材料:橡胶底(防滑)、透气网布
制作运动鞋:缝合鞋底与鞋面
将运动鞋装入包装盒
客户取走运动鞋

客户下单:leather鞋
准备皮鞋材料:橡胶底(耐磨)、牛皮
制作皮鞋:缝合鞋底与鞋面
将皮鞋装入包装盒
客户取走皮鞋

解决的问题

  • 鞋店(ShoeStore)彻底解放,只负责销售,不用关心制作流程。
  • 制作流程标准化(所有鞋都经过"准备→制作→包装"),质量更稳定。
  • 新增鞋类时,鞋店代码无需修改(符合开闭原则)。

三、工厂方法:按产品类型分设车间

场景升级

你的鞋厂名气越来越大,决定新增"凉鞋"产品线。但问题来了:运动鞋需要防滑测试,皮鞋需要皮质检测,凉鞋需要防水测试------简单工厂的一条流水线无法满足不同产品的特殊流程,效率低下。

解决办法:按产品类型分设车间------运动鞋车间专门生产运动鞋,皮鞋车间专门生产皮鞋,每个车间有自己的特殊工艺。

模式定义

工厂方法为每种产品设立专属工厂,每个工厂只生产一种产品,并负责该产品的全部生产流程(包括特殊工艺)。客户端通过选择不同工厂来获取对应产品。

代码实现(分车间生产)

java 复制代码
// 1. 抽象产品:鞋子(同上,新增特殊工艺方法)
public abstract class Shoe {
    // ... 原有代码 ...
    public abstract void specialProcess(); // 特殊工艺(不同鞋不一样)
}

// 2. 具体产品:运动鞋(新增防滑测试)
public class SportsShoe extends Shoe {
    // ... 原有代码 ...
    @Override
    public void specialProcess() {
        System.out.println("运动鞋特殊工艺:防滑测试");
    }
}

// 2. 具体产品:皮鞋(新增皮质检测)
public class LeatherShoe extends Shoe {
    // ... 原有代码 ...
    @Override
    public void specialProcess() {
        System.out.println("皮鞋特殊工艺:皮质检测");
    }
}

// 3. 抽象工厂:鞋厂车间接口(定义生产流程)
public interface ShoeFactory {
    Shoe produceShoe(); // 生产鞋子
}

// 4. 具体工厂:运动鞋车间
public class SportsShoeFactory implements ShoeFactory {
    @Override
    public Shoe produceShoe() {
        System.out.println("===== 运动鞋车间 =====");
        Shoe shoe = new SportsShoe();
        shoe.prepare();
        shoe.make();
        shoe.specialProcess(); // 执行运动鞋特殊工艺
        shoe.box();
        return shoe;
    }
}

// 4. 具体工厂:皮鞋车间
public class LeatherShoeFactory implements ShoeFactory {
    @Override
    public Shoe produceShoe() {
        System.out.println("===== 皮鞋车间 =====");
        Shoe shoe = new LeatherShoe();
        shoe.prepare();
        shoe.make();
        shoe.specialProcess(); // 执行皮鞋特殊工艺
        shoe.box();
        return shoe;
    }
}

// 5. 客户端:鞋店(根据客户需求选择车间)
public class ShoeStore {
    // 传入具体工厂,而非产品类型
    public Shoe sellShoe(ShoeFactory factory) {
        System.out.println("客户下单,通知对应车间生产");
        Shoe shoe = factory.produceShoe();
        System.out.println("客户取走" + shoe.name + "\n");
        return shoe;
    }
    
    public static void main(String[] args) {
        ShoeStore store = new ShoeStore();
        // 卖运动鞋:找运动鞋车间
        store.sellShoe(new SportsShoeFactory());
        // 卖皮鞋:找皮鞋车间
        store.sellShoe(new LeatherShoeFactory());
    }
}

运行结果

复制代码
客户下单,通知对应车间生产
===== 运动鞋车间 =====
准备运动鞋材料:橡胶底(防滑)、透气网布
制作运动鞋:缝合鞋底与鞋面
运动鞋特殊工艺:防滑测试
将运动鞋装入包装盒
客户取走运动鞋

客户下单,通知对应车间生产
===== 皮鞋车间 =====
准备皮鞋材料:橡胶底(耐磨)、牛皮
制作皮鞋:缝合鞋底与鞋面
皮鞋特殊工艺:皮质检测
将皮鞋装入包装盒
客户取走皮鞋

新增产品的优势

当需要新增"凉鞋"时,只需添加两个类,原有代码完全不用改:

java 复制代码
// 新增具体产品:凉鞋
public class Sandal extends Shoe {
    public Sandal() { name = "凉鞋"; }
    @Override
    public void prepare() { /* 准备塑料鞋底和帆布 */ }
    @Override
    public void specialProcess() {
        System.out.println("凉鞋特殊工艺:防水测试");
    }
}

// 新增具体工厂:凉鞋车间
public class SandalFactory implements ShoeFactory {
    @Override
    public Shoe produceShoe() {
        System.out.println("===== 凉鞋车间 =====");
        // ... 生产流程 ...
        return new Sandal();
    }
}

// 客户端直接使用新车间
store.sellShoe(new SandalFactory()); // 无需修改鞋店代码

这完美符合"开闭原则"------扩展开放,修改关闭

四、抽象工厂:按品牌设立生产线

场景再升级

你的鞋厂开始代工国际品牌,比如耐克(Nike)和阿迪达斯(Adidas)。每个品牌不仅有自己的运动鞋,还有配套的鞋盒、标签------这些产品需要风格统一(比如耐克的logo、配色)。

此时需要解决的问题:确保同一品牌的系列产品风格一致(如耐克运动鞋+耐克鞋盒+耐克标签)。这就是抽象工厂要解决的"产品族"问题。

模式定义

抽象工厂用于生产一系列相互关联的产品族(如"耐克品牌的鞋+鞋盒+标签")。每个具体工厂对应一个品牌,负责生产该品牌的所有配套产品,确保风格统一。

代码实现(品牌代工场景)

java 复制代码
// 1. 抽象产品族:鞋子、鞋盒、标签(同一品牌需风格统一)
public interface Shoe { void showBrand(); }
public interface ShoeBox { void showBrand(); }
public interface Label { void showBrand(); }

// 2. 具体产品族1:耐克(Nike)
public class NikeShoe implements Shoe {
    @Override
    public void showBrand() { System.out.println("耐克运动鞋(勾形logo)"); }
}
public class NikeBox implements ShoeBox {
    @Override
    public void showBrand() { System.out.println("耐克鞋盒(红色)"); }
}
public class NikeLabel implements Label {
    @Override
    public void showBrand() { System.out.println("耐克标签(材质:纸质)"); }
}

// 2. 具体产品族2:阿迪达斯(Adidas)
public class AdidasShoe implements Shoe {
    @Override
    public void showBrand() { System.out.println("阿迪运动鞋(三道杠logo)"); }
}
public class AdidasBox implements ShoeBox {
    @Override
    public void showBrand() { System.out.println("阿迪鞋盒(蓝色)"); }
}
public class AdidasLabel implements Label {
    @Override
    public void showBrand() { System.out.println("阿迪标签(材质:布质)"); }
}

// 3. 抽象工厂:品牌生产线(定义生产所有配套产品的接口)
public interface BrandFactory {
    Shoe createShoe();
    ShoeBox createShoeBox();
    Label createLabel();
}

// 4. 具体工厂1:耐克生产线
public class NikeFactory implements BrandFactory {
    @Override
    public Shoe createShoe() { return new NikeShoe(); }
    @Override
    public ShoeBox createShoeBox() { return new NikeBox(); }
    @Override
    public Label createLabel() { return new NikeLabel(); }
}

// 4. 具体工厂2:阿迪生产线
public class AdidasFactory implements BrandFactory {
    @Override
    public Shoe createShoe() { return new AdidasShoe(); }
    @Override
    public ShoeBox createShoeBox() { return new AdidasBox(); }
    @Override
    public Label createLabel() { return new AdidasLabel(); }
}

// 5. 客户端:代工厂组装车间(按品牌组装产品)
public class AssemblyLine {
    private Shoe shoe;
    private ShoeBox box;
    private Label label;
    
    // 传入品牌工厂,确保所有产品风格统一
    public AssemblyLine(BrandFactory factory) {
        this.shoe = factory.createShoe();
        this.box = factory.createShoeBox();
        this.label = factory.createLabel();
    }
    
    public void assemble() {
        System.out.println("开始组装品牌产品:");
        shoe.showBrand();
        box.showBrand();
        label.showBrand();
        System.out.println("组装完成\n");
    }
    
    public static void main(String[] args) {
        // 组装耐克产品(所有组件都是耐克)
        AssemblyLine nikeLine = new AssemblyLine(new NikeFactory());
        nikeLine.assemble();
        
        // 组装阿迪产品(所有组件都是阿迪)
        AssemblyLine adidasLine = new AssemblyLine(new AdidasFactory());
        adidasLine.assemble();
    }
}

运行结果

复制代码
开始组装品牌产品:
耐克运动鞋(勾形logo)
耐克鞋盒(红色)
耐克标签(材质:纸质)
组装完成

开始组装品牌产品:
阿迪运动鞋(三道杠logo)
阿迪鞋盒(蓝色)
阿迪标签(材质:布质)
组装完成

核心价值

抽象工厂确保了同一产品族的兼容性------你永远不会得到"耐克运动鞋+阿迪鞋盒"的组合,这在需要统一风格的场景(如品牌代工、跨平台UI组件)中至关重要。

五、三种工厂模式的对比:该用哪一种?

模式类型 现实场景类比 核心优势 适合情况
简单工厂 小型流水线(一条线生产多种鞋) 实现简单,集中管理创建逻辑 产品少且变化不频繁(如只有2-3种鞋)
工厂方法 按产品分车间(运动鞋车间、皮鞋车间) 扩展灵活,符合开闭原则 产品多或经常新增产品(如不断推出新鞋型)
抽象工厂 按品牌分生产线(耐克线、阿迪线) 保证产品族的一致性 需要生产系列配套产品(如鞋+鞋盒+标签)

用一句话总结:

  • 简单工厂是"一厂多品"
  • 工厂方法是"一厂一品"
  • 抽象工厂是"一厂一族"

六、工厂模式的设计本质

从制鞋厂的例子可以看出,工厂模式的核心不是"创建工厂类",而是建立"创建者"与"产品"之间的隔离带

  • 让"创建者"(工厂)专注于"如何生产"(封装变化的创建逻辑)。
  • 让"使用者"(客户端)专注于"如何使用"(依赖稳定的抽象接口)。

这种隔离带来了两大好处:

  1. 灵活性:更换产品时,只需更换工厂,无需修改使用者代码(如鞋店换个车间就能卖新鞋)。
  2. 稳定性:产品创建逻辑的变化不会影响使用者(如车间改进工艺,鞋店卖鞋流程不变)。

总结:从鞋厂到代码的启示

工厂模式就像制鞋厂的管理体系:

  • 小作坊(简单场景)用简单工厂,快速高效。
  • 多产品线的中型工厂用工厂方法,灵活扩展。
  • 生产系列产品的大型企业用抽象工厂,保证一致性。

在代码中,当发现"对象创建逻辑散落在业务代码中""新增产品需要修改多处代码"时,不妨想想制鞋厂的例子------是时候引入工厂模式,给你的代码建一条"标准化生产线"了。


Studying will never be ending.

▲如有纰漏,烦请指正~~

相关推荐
WaWaJie_Ngen4 小时前
【设计模式】建造者模式(Builder)
设计模式·建造者模式
四谎真好看4 小时前
Java 黑马程序员学习笔记(进阶篇20)
java·笔记·学习·学习笔记
BUTCHER54 小时前
【原理扫描】SSL/TLS 服务器瞬时 Difie-Hellman 公共密钥过弱
java·服务器·网络·ssl
聪明的笨猪猪4 小时前
hot 100 (1)—— 两数之和(哈希)
java·经验分享·算法·哈希算法
梵得儿SHI4 小时前
Java 注解与反射实战:自定义注解从入门到精通
java·开发语言·注解·自定义注解·元注解·控制注解的作用·声明式编程思想
沐知全栈开发4 小时前
Foundation 网格实例
开发语言
专注前端30年5 小时前
【JavaScript】every 方法的详解与实战
开发语言·前端·javascript
速易达网络5 小时前
Java Web登录系统实现(不使用开发工具)
java·开发语言·前端
凡间客5 小时前
Python编程之常用模块
开发语言·python