C# 简单工厂模式详解:从名字解析到数学计算
简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它通过一个工厂类根据输入参数决定返回哪一个具体类的实例。这种模式不严格属于GoF(四人组)设计模式,但因其简单易懂、功能明确,被广泛应用于软件开发中。封装对象创建逻辑:客户端无需关心对象的创建过程。解耦客户端与具体类:客户端只与接口或抽象类交互。提高可扩展性:新增类时只需修改工厂类,符合开放封闭原则。imag = i
工厂模式(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′=R1−R2cos(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′=I1−R2sin(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′=R1−R2(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′=I1−I2(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算法,工厂模式都能帮助我们写出更清晰、更可维护的代码。
从名字解析到数学计算,我们看到了工厂模式如何跨越不同领域,解决不同层面的问题。它不仅是一种编程技巧,更是架构设计中的一种思维方式。在实际开发中,合理使用工厂模式,能够显著提升代码质量,增强系统的稳定性和可扩展性。
未来展望:随着系统复杂度的提升,工厂模式可以进一步演进为工厂方法模式或抽象工厂模式,以应对更复杂的对象创建需求。在微服务、插件系统、配置驱动等架构中,工厂模式依然是不可或缺的基石之一。
更多推荐
所有评论(0)