工厂模式(Factory Pattern)是面向对象编程中的一种常见设计模式,它通过封装对象的创建逻辑,将对象的创建与使用分离。这种方式不仅提高了代码的灵活性,还增强了系统的可扩展性。本文将从一个简单的名字解析案例出发,深入探讨工厂模式的应用,并进一步扩展到数学计算中的工厂实现,全面解析其原理与实践。


一、什么是简单工厂模式?

简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它通过一个工厂类根据输入参数决定返回哪一个具体类的实例。这种模式不严格属于GoF(四人组)设计模式,但因其简单易懂、功能明确,被广泛应用于软件开发中。

核心思想:

  • 封装对象创建逻辑:客户端无需关心对象的创建过程。
  • 解耦客户端与具体类:客户端只与接口或抽象类交互。
  • 提高可扩展性:新增类时只需修改工厂类,符合开放封闭原则。

二、案例一:名字格式解析中的工厂模式

在实际开发中,用户输入的名字可能以“姓,名”或“名 姓”等形式存在。为了解析这类数据,我们可以定义一个统一的接口,并根据输入格式返回不同的解析类。

1. 接口定义

public abstract class Namer
{
    public abstract string getFrname();
    public abstract string getLname();
}

2. 具体实现类

  • FirstFirst:用于处理“名 姓”格式。
  • LastFirst:用于处理“姓,名”格式。
public class FirstFirst : Namer
{
    string name;
    public FirstFirst(string name) { this.name = name; }
 
    public override string getFrname() { return name.Split(' ')[0]; }
    public override string getLname() { return name.Split(' ')[1]; }
}
 
public class LastFirst : Namer
{
    string name;
    public LastFirst(string name) { this.name = name; }
 
    public override string getFrname() { return name.Substring(name.IndexOf(",") + 1).Trim(); }
    public override string getLname() { return name.Substring(0, name.IndexOf(",")).Trim(); }
}

3. 工厂类

public class NameFactory
{
    public Namer getName(string name)
    {
        int i = name.IndexOf(",");
        if (i > 0)
            return new LastFirst(name);
        else
            return new FirstFirst(name);
    }
}

4. 客户端调用

private void btCompute_click(object sender, EventArgs e)
{
    Namer nm = nameFact.getName(txName.Text);
    txFirst.Text = nm.getFrname();
    txLast.Text = nm.getLname();
}

设计意图:通过工厂类自动判断输入格式,返回适配的解析类,避免了客户端手动判断和实例化带来的耦合。


三、案例二:数学计算中的工厂模式(FFT蝴蝶结构)

在数学计算中,尤其是像快速傅里叶变换(FFT)这样的复杂数值运算中,工厂模式同样大有用武之地。

1. 问题背景

FFT中“蝴蝶结构”(Butterfly)是核心操作单元,它根据输入角度决定使用哪一组公式进行计算:

通用公式(y ≠ 0时):

R1′=R1+R2cos⁡(y)−I2sin⁡(y)(1) R_1' = R_1 + R_2\cos(y) - I_2\sin(y) \quad (1) R1=R1+R2cos(y)I2sin(y)(1)
R2′=R1−R2cos⁡(y)+I2sin⁡(y)(2) R_2' = R_1 - R_2\cos(y) + I_2\sin(y) \quad (2) R2=R1R2cos(y)+I2sin(y)(2)
I1′=I1+R2sin⁡(y)+I2cos⁡(y)(3) I_1' = I_1 + R_2\sin(y) + I_2\cos(y) \quad (3) I1=I1+R2sin(y)+I2cos(y)(3)
I2′=I1−R2sin⁡(y)−I2cos⁡(y)(4) I_2' = I_1 - R_2\sin(y) - I_2\cos(y) \quad (4) I2=I1R2sin(y)I2cos(y)(4)

简化公式(y = 0时):

R1′=R1+R2(5) R_1' = R_1 + R_2 \quad (5) R1=R1+R2(5)
R2′=R1−R2(6) R_2' = R_1 - R_2 \quad (6) R2=R1R2(6)
I1′=I1+I2(7) I_1' = I_1 + I_2 \quad (7) I1=I1+I2(7)
I2′=I1−I2(8) I_2' = I_1 - I_2 \quad (8) I2=I1I2(8)

工厂模式可根据角度值自动选择使用哪一组公式。


2. 数据结构定义

public class Complex
{
    float real, imag;
    public Complex(float r, float i) { real = r; imag = i; }
 
    // getter/setter 省略
}

3. 抽象基类与具体实现

public abstract class Butterfly
{
    public abstract void Execute(Complex xi, Complex xj);
}

加法类(AddButterfly)

适用于 y = 0 时的简化公式:

public class AddButterfly : Butterfly
{
    public override void Execute(Complex xi, Complex xj)
    {
        float oldr1 = xi.getReal(), oldi1 = xi.getImag();
 
        xi.setReal(oldr1 + xj.getReal());
        xj.setReal(oldr1 - xj.getReal());
        xi.setImag(oldi1 + xj.getImag());
        xj.setImag(oldi1 - xj.getImag());
    }
}

三角类(TrigButterfly)

适用于 y ≠ 0 的通用公式:

public class TrigButterfly : Butterfly
{
    float y, cosy, siny;
 
    public TrigButterfly(float angle)
    {
        y = angle;
        cosy = (float)Math.Cos(y);
        siny = (float)Math.Sin(y);
    }
 
    public override void Execute(Complex xi, Complex xj)
    {
        float oldr1 = xi.getReal(), oldi1 = xi.getImag();
        float r2 = xj.getReal(), i2 = xj.getImag();
 
        float r2cosy = r2 * cosy;
        float r2siny = r2 * siny;
        float i2cosy = i2 * cosy;
        float i2siny = i2 * siny;
 
        xi.setReal(oldr1 + r2cosy - i2siny);
        xi.setImag(oldi1 + r2siny + i2cosy);
        xj.setReal(oldr1 - r2cosy + i2siny);
        xj.setImag(oldi1 - r2siny + i2cosy);
    }
}

4. 工厂类(Cocoon)

public class Cocoon
{
    static public Butterfly getButterfly(float y)
    {
        if (y != 0)
            return new TrigButterfly(y);
        else 
            return new AddButterfly(y);
    }
}

5. 客户端调用示例

Butterfly bf = Cocoon.getButterfly(angle);
bf.Execute(x1, x2);

设计意图:通过工厂类根据角度值动态选择合适的计算类,避免重复判断和冗余逻辑,使数学计算模块更清晰、高效。


四、工厂模式的优势与适用场景

优势 说明
解耦对象创建与使用 客户端无需关心类的构造细节,只需使用接口。
易于扩展 增加新的类只需扩展工厂类,不需修改已有代码。
逻辑集中管理 所有创建逻辑集中于工厂类,提高可维护性。
适应多种输入条件 可根据输入参数(如字符串格式、角度值等)返回不同类实例。

适用场景:

  • 多种格式的数据解析(如本文中的名字解析)
  • 数值计算中根据条件选择不同算法(如本文FFT中的Butterfly)
  • 多种支付方式、数据库连接、日志记录等系统设计
  • 插件系统中动态加载不同插件类

五、总结:工厂模式的价值与思考

简单工厂模式虽然简单,却蕴含了面向对象设计的核心思想——封装变化、解耦依赖。无论是在业务逻辑中处理字符串格式,还是在数学计算中优化FFT算法,工厂模式都能帮助我们写出更清晰、更可维护的代码。

从名字解析到数学计算,我们看到了工厂模式如何跨越不同领域,解决不同层面的问题。它不仅是一种编程技巧,更是架构设计中的一种思维方式。在实际开发中,合理使用工厂模式,能够显著提升代码质量,增强系统的稳定性和可扩展性。


未来展望:随着系统复杂度的提升,工厂模式可以进一步演进为工厂方法模式或抽象工厂模式,以应对更复杂的对象创建需求。在微服务、插件系统、配置驱动等架构中,工厂模式依然是不可或缺的基石之一。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐