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

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

maynowei9个月前 (09-29)技术知识111



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

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


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

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


记忆口诀:

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

相关文章

Objective-C的本质(objective-c的特点)

我们平时编写的Objective-C代码,底层实现其实都是C\C++代码,所以Objective-C的面向对象都是基于C\C++的数据结构实现的OC对象的本质Objective-C的对象、类主要是基于...

那些技术—Listview的性能提高篇(listview提高效率)

ListView优化一直是一个老生常谈的问题,不管是面试还是平常的开发中,ListView永远不会被忽略掉,那么这篇文章我们来看看如何最大化的优化ListView的性能。 · 1.在adapter中的...

Android之自定义ListView(一)(android 自定义view绘制流程)

PS:自定义View是Android中高手进阶的路线.因此我也打算一步一步的学习.看了鸿洋和郭霖这两位大牛的博客,决定一步一步的学习,循序渐进.学习内容:1.自定义View实现ListView的Ite...

btrace 3.0 重磅新增 iOS 支持!免插桩原理大揭秘!

重磅更新btrace 是由字节跳动抖音基础技术团队自主研发的面向移动端的性能数据采集工具,它能够高效的助力移动端应用采集性能 Trace 数据,深入剖析代码的运行状况,进而辅助优化提升移动端应用的性能...

从 async/await 到虚拟线程:Python 并发的再思考

演进之路:从async/await到线程的反思首先必须明确的是,async/await对Python并非全无裨益:它最大的价值,是让更多人接触到了并发编程。通过在编程语言中嵌入语法元素,并发编程的门槛...

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

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