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

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

maynowei5个月前 (09-29)技术知识62



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

工厂方法模式(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;
—— 现有代码一行不改!这就是开闭原则的力量!


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

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


记忆口诀:

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

相关文章

Axure案例小红书APP登陆界面划屏效果制作

有一款叫做小红书的APP(不是小黄书)登陆界面做的非常清新脱俗,教他家用Axure模仿练习一下他的登陆界面划屏效果,这个内容虽然有些多,但是制作方法并不难,耐心跟着做的话肯定没问题哒!点击观看效果效果...

Go语言进阶:时间轮(golang时间轮)

时间轮概念时间轮(Timing Wheel)是一种高效的定时任务调度数据结构,特别适合处理大量定时任务。它通过一个循环数组(轮盘)和多个槽位(buckets)来组织定时任务,每个槽位代表一个时间间隔。...

centos系统安装oracle简易客户端instantclient

一、目录1:centos 环境准备2:instant client 下载3:instant client 安装4:instant client 配置5:测试连接二、安装步骤1:zip,unzip命令安...

Google前工程主管“入住”Oracle(google公司前台)

ZDNet至顶网服务器频道 10月11日 新闻消息:Oracle 已聘用了前 Snapchat 和 Google 工程部主管 Peter Magnusson,其主要的职责是运行一个被重新调整过的 of...

oracle和mysql的优缺点对比(oracle和mysql哪个简单)

oracle的优缺点优点:开放性:oracle 能所有主流平台上运行(包括 windows)完全支持所有工业标准采用完全开放策略使客户选择适合解决方案对开发商全力支持;可伸缩性,并行性:Oracle...

Docker安装Oracle 11g 数据库过程详解

1、查看docker 版本[root@node3 ~]# docker version Client: Version: 18.09.6 API version:...