当前位置:首页 > 技术知识 > 正文内容

设计模式之-工厂方法_工厂设计模式的优点

maynowei8个月前 (09-29)技术知识92



一、【概念定义】—— “让子类决定造什么”的生产术

工厂方法模式(Factory Method Pattern)
一种“延迟实例化型”创建型设计模式,它
定义一个用于创建对象的接口(工厂方法),但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类
核心思想:
“不直接new,而是调用工厂方法;具体造什么,子类说了算”
目标:
解耦对象创建与使用,支持灵活扩展新产品,符合开闭原则

口诀:“创建对象我不干,工厂方法来接盘;子类决定造哪个,扩展新品不用改!”


二、【解决的问题】—— “手搓对象”的三大灾难

想象你正在开发一个跨平台UI框架

  • 直接创建:
    if (platform == "iOS") button = new iOSButton(); else button = new AndroidButton();
    → 代码中遍布条件判断!新增“Windows按钮”?全局搜索替换!
  • 工厂方法模式:
    • 定义 ButtonFactory.createButton() 抽象方法;
    • iOSButtonFactory → 返回 iOSButton;
    • AndroidButtonFactory → 返回 AndroidButton;
      → 客户端只需调用 factory.createButton(),
      具体类型由工厂子类决定

核心解决:

硬编码创建 → 创建逻辑封装到工厂;扩展困难 → 新增产品?只需新增工厂子类;违反开闭原则 → 工厂方法让系统对扩展开放,对修改关闭!


三、【适用场景】—— “需要灵活创建对象”的四大战场

你该用工厂方法模式,如果符合以下“四需原则”:

场景

描述

举例

对象创建逻辑复杂

初始化需多步、依赖配置或环境

数据库连接、日志记录器、网络客户端

需要解耦创建与使用

客户端不想知道具体类名

UI控件、游戏道具、支付网关

支持扩展新产品

未来会新增同类产品,且不希望修改现有代码

新增支付方式(支付宝、微信)、新增图表类型

隐藏具体实现

只暴露接口,隐藏具体类(如第三方库)

框架提供接口,用户实现自己的工厂

警告:如果对象创建简单(如 new User()),且无扩展需求 —— 工厂方法是过度设计!


四、【经典案例】—— 四大“流水线王者”的成名战

1. 【跨平台UI控件】—— 一套代码,多端运行!

需要在iOS、Android、Web创建不同风格的按钮
直接new:每个界面文件写满平台判断 → 维护噩梦!
工厂方法:

ButtonFactory(抽象工厂);
iOSButtonFactory.createButton() → 返回 iOSButton;
AndroidButtonFactory.createButton() → 返回 AndroidButton;客户端:factory.createButton().render();

效果:新增“WebButton”?只需新增 WebButtonFactory!
零修改现有代码!

2. 【支付网关系统】—— 新增支付方式?小菜一碟!

支持支付宝、微信支付,未来要加银联、PayPal
直接new:if(type=="alipay") pay = new Alipay(); → 每次加新支付方式都要改支付模块!
工厂方法:


PaymentFactory.createPayment();AlipayFactory → new Alipay();WeChatPayFactory → new WeChatPay();客户端:factory.createPayment().pay(amount);

效果:新增“PayPal”?只需 PayPalFactory!支付模块
纹丝不动

3. 【游戏道具生成】—— 关卡不同,道具不同!

关卡1掉落“生命药水”,关卡2掉落“魔法卷轴”
直接new:if(level==1) item = new HealthPotion(); → 关卡多了代码爆炸!
工厂方法:

ItemFactory.createItem();Level1ItemFactory → new HealthPotion();Level2ItemFactory → new MagicScroll();关卡管理器:factory.createItem().use();
效果:新增关卡3?只需 Level3ItemFactory!
关卡逻辑与道具创建彻底解耦!

4. 【数据库连接池】—— 换数据库?配置搞定!

支持MySQL、PostgreSQL,未来可能换Oracle
直接new:conn = new MySQLConnection() → 换数据库?全局替换!
工厂方法:


DBConnectionFactory.createConnection();MySQLFactory → new MySQLConnection();PostgreSQLFactory → new PostgreSQLConnection();客户端:factory.createConnection().query(sql);

效果:换Oracle?只需 OracleFactory + 配置文件切换!
代码无需修改!


五、【结构简述】—— 工厂宇宙的“生产四剑客”

工厂方法四要素:

角色

职责

比喻

Product(抽象产品)

声明产品接口

“产品蓝图” —— 所有按钮都要有 render() 方法

ConcreteProduct(具体产品)

实现产品接口的具体类

“具体商品” —— iOS按钮、Android按钮

Creator(抽象工厂)

声明工厂方法(通常抽象),可包含其他业务逻辑

“工厂蓝图” —— 声明 createButton() 方法

ConcreteCreator(具体工厂)

实现工厂方法,返回具体产品实例

“具体流水线” —— iOS工厂、Android工厂

调用流程:
Client → 持有 ConcreteCreator → 调用 creator.createProduct() → 返回 ConcreteProduct → 使用 product.method()


六、【注意事项】—— “流水线”虽强,小心“过度设计”!

1. 类数量膨胀

每个产品对应一个工厂子类 → 类数量翻倍!
解决:

简单工厂(静态工厂)代替(如果无需扩展);用反射+配置文件动态创建(如 Spring 的 @Bean);权衡:扩展性需求 > 类数量成本 时使用。

2. 客户端需知道具体工厂

客户端必须创建 iOSButtonFactory 或 AndroidButtonFactory → 仍需知道具体类!
解决:

抽象工厂模式封装工厂创建;用依赖注入(如 Spring)自动注入工厂;用配置文件/环境变量决定实例化哪个工厂。

3. 性能开销

多一层工厂方法调用 → 轻微性能损耗(通常可忽略)
权衡:灵活性收益 >> 性能损耗 时使用。

4. 工厂方法 vs 简单工厂

简单工厂:一个工厂类 + 静态方法 + 条件判断 → 不符合开闭原则工厂方法:多个工厂子类 → 符合开闭原则
选择:产品稳定、无需扩展 → 简单工厂;产品需扩展、追求开闭 → 工厂方法。


七、【实战应用】—— 30行代码,打造“跨平台按钮工厂”

java

深色版本

// 1. 抽象产品
interface Button {
    void render();
}

// 2. 具体产品
class iOSButton implements Button {
    @Override
    public void render() {
        System.out.println(" 渲染iOS风格按钮 (圆角+毛玻璃)");
    }
}

class AndroidButton implements Button {
    @Override
    public void render() {
        System.out.println(" 渲染Android风格按钮 (Material Design)");
    }
}

// 3. 抽象工厂
abstract class ButtonFactory {
    // 工厂方法(抽象)
    public abstract Button createButton();

    // 其他业务逻辑(可选)
    public void renderButton() {
        Button button = createButton(); // 子类决定创建哪个
        button.render();
    }
}

// 4. 具体工厂
class iOSButtonFactory extends ButtonFactory {
    @Override
    public Button createButton() {
        return new iOSButton();
    }
}

class AndroidButtonFactory extends ButtonFactory {
    @Override
    public Button createButton() {
        return new AndroidButton();
    }
}

// 5. 客户端
public class FactoryMethodDemo {
    public static void main(String[] args) {
        System.out.println(" 跨平台UI框架启动...");

        // 模拟:根据配置选择平台
        String platform = "iOS"; // 可改为 "Android"

        ButtonFactory factory;
        if ("iOS".equals(platform)) {
            factory = new iOSButtonFactory();
        } else {
            factory = new AndroidButtonFactory();
        }

        System.out.println(" 当前平台: " + platform);
        factory.renderButton(); // 工厂方法创建并渲染按钮

        // 新增平台?只需新增工厂类!无需修改此代码!
    }
}

运行结果(platform = "iOS"):

深色版本
 跨平台UI框架启动...
 当前平台: iOS
 渲染iOS风格按钮 (圆角+毛玻璃)

运行结果(platform = "Android"):

深色版本
 跨平台UI框架启动...
 当前平台: Android
 渲染Android风格按钮 (Material Design)

看到了吗?客户端完全不知道具体按钮类!它只和 ButtonFactory 交互!新增“WebButton”?只需:

创建 WebButton implements Button;创建 WebButtonFactory extends ButtonFactory;在配置中选择 WebButtonFactory;
—— 现有代码一行不改!这就是开闭原则的力量!


最后总结:工厂方法模式 —— 对象界的“智能流水线”

以前:对象手搓 → 代码僵化,扩展困难;
现在:工厂流水线 → 子类决定生产什么,扩展新品如搭积木!
工厂方法模式就是对象界的“可扩展生产线” ——
把“造什么”的决定权交给子类,让系统在变化中岿然不动!


记忆口诀:

对象创建太麻烦,
工厂方法来分担。
抽象工厂定接口,
具体工厂造产品。
子类决定实例化,
扩展新品不用改!
跨平台与支付网,
流水线它最划算!
莫为简单对象忙,
需求到位再登场!

相关文章

Windows 加密盘BitLocker爆锁屏绕过严重漏洞

BitLocker Windows内置现代设备级数据加密保护功能,BitLocker与Windows内核深度集成。有大量的企业和个人使用BitLocker加密自己关键数据,以防止数据泄密。BitLoc...

有了这份900多页的Android面试指南,你离大厂Offer还远吗?

前言对于大部分程序员来说,一线互联网是的工作经历是毕生的追求,实际上大厂对于学历的要求远远没有我们想象的那么高,近几年来,互联网公司更注重技术,所以提升自身技术水平才是斩获offer的制胜关键。一线互...

android培训学习的大纲(安卓app培训)

第一阶段android基础:1.基础javaJava概述,进制,数据类型,常量变量,运算符,表达式关系运算符,逻辑运算符,if语句,switch语句while循环,do...while循环,for循环...

一文弄懂 GO 的 互斥锁 Mutex !(互斥锁的使用方法)

在 Go 语言并发编程中,互斥锁(Mutex)是一个非常重要的同步原语。本文将深入介绍 Mutex 的使用方法、实现原理以及最佳实践。1. 什么是 Mutex?Mutex(互斥锁)是一种用于多线程编程...

大厂 Go 编程规范(二):mutex(编程大厂是什么意思)

mutex 是golang 的互斥锁,可以保障在多协程的情况下,数据访问的安全。1、零值有效我们并不需要mutex指针mu := new(sync.Mutex) mu.Lock()直接可以使用mute...

go语言并发原语RWMutex实现原理及闭坑指南

1.RWMutex常用方法Lock/UnlockRLock/RUnlockRLocker 为读操作返回一个Locker接 口的对象2. RWMutex使用方法 func main() { var c...