Table of Contents
导言
工程数据处理系统必须处理越来越多的各种输入格式——从标准的CSV和JSON文件到CAD、模拟和IOT传感器流中使用的专门专有系统。确保这些格式之间的兼容性而不重写核心逻辑是一个长期的挑战。工厂方法模式提供了一个结构化的解决方案:它包罗了共同界面后面的物体创建,让子类决定哪个具体类别来即时处理。这一篇文章解释了如何在工程数据处理中应用工厂方法模式,包括实际步骤、现实世界实例和对其好处的讨论。我们还可以看到这种模式如何与诸如Directus这样的工具相配合,Directus是一种无头的CMS,它常常处理不同的数据源。
了解工厂方法模式
工厂方法模式是来自四人帮的创作设计模式,其核心思想是定义一个创建对象的界面或抽象类,但允许子类更改将要创建的对象类型,这促进了开放/封闭原则:一个系统开放扩展(新产品类型),但关闭修改(现有代码保持不变).
在类图中,图案包括:
- Production – 一种界面或抽象类,定义所有具体产品必须执行的操作.
- 具体产品Production – 产品接口的具体实施.
- 创造器[] — 一个抽象的类,它宣布工厂方法(通常). 创建者可能还包括将工厂方法称为商业逻辑.
- 具体制造器[] – 取代工厂方法的子类,以返回混凝土产品实例.
这种将创造逻辑与商业逻辑分开,是使得模式在数据处理管道中如此强大的原因.
工程数据处理为何需要工厂
工程组往往采用不同的数据格式。
- 解析 HDF5, CSV, 和专有二进制格式的模拟输出文件.
- 从 XML, YAML 或环境变量读取配置数据.
- 从STEP, IGES, 或本地软件格式导入 CAD 模型.
- 通过MQTT,HTTP流,或WebSockets,来控制实时传感器数据.
如果没有设计模式,开发者可能会将代码库中包含或]语句,以选择正确的阅读器。这使得系统简洁的添加新格式需要修改这些有条件的分支,增加错误的机会。工厂方法模式将选择逻辑移动到专门的子类中,所以添加新格式意味着添加一个新的混凝土创建者和一个新的混凝土产品,使现有的代码没有被改变。
步步执行
让我们以语言不可知的风格走过一个实际的实现。 (同样的逻辑同样适用于 Java, C#, TypeScript, Python, 或 PHP 。 )
步骤1:定义产品接口
创建所有数据读取器都将执行的界面。该界面定义了读取和可能转换数据的方法。
interface DataReader {
void readData();
List<Record> getRecords();
}
步骤2:创建具体执行
执行每种支持格式的界面。
class CSVReader implements DataReader {
// … constructor, parsing logic …
public void readData() { … }
public List<Record> getRecords() { … }
}
class JSONReader implements DataReader {
// … similar …
}
步骤3:用工厂方法定义创建者
抽象创建类宣布工厂方法,也可能包含使用该产品的常见处理逻辑.
abstract class DataReaderFactory {
// Factory method
abstract DataReader createReader();
// Template method that uses the product
public List<Record> processData() {
DataReader reader = createReader();
reader.readData();
return reader.getRecords();
}
}
步骤4:实施具体工厂
每个子类都超越工厂的方法,以返回一个特定的读取器.
class CSVReaderFactory extends DataReaderFactory {
@Override
DataReader createReader() {
return new CSVReader("input.csv");
}
}
class JSONReaderFactory extends DataReaderFactory {
@Override
DataReader createReader() {
return new JSONReader("input.json");
}
}
现在,客户端代码可以和抽象工厂合作,并根据配置或运行时间条件选择合适的混凝土工厂:
DataReaderFactory factory = getFactoryFromConfig(); // e.g., returns CSVReaderFactory
List<Record> records = factory.processData();
客户端从不直接即时化一个或——它只与抽象工厂和产品界面相互作用,这种脱钩是图案的本质.
添加新格式
假设我们必须支持 XML。 我们只需要创建:
- ]]
- []]
不需要其他代码更改。 工厂方法模式使系统真正可以扩展 。
工程领域实际世界应用
工厂方法模式在工程软件中是普遍存在的。
CAD 文件导入器
CAD 应用程序必须读取 STEP(AP203/AP214) 的几何图形, IGES 和 SolidWorks SLDPRT 等供应商专用格式。每种格式都有完全不同的解析器。厂家方法让应用程序根据文件扩展或用户选择确定正确的导入者。其余应用程序都使用统一的几何表示。
传感器数据聚合
一个IOT平台从使用MQTT,CoAP,HTTP POST和专有二进制协议的设备中收集遥测数据. 工厂模式创建了适当的协议处理器,使数据摄入引擎能够统一处理所有来的数据.
直线和无头CMS
Directus 是一种流行的无头内容CMS,它管理来自许多来源的内容——数据库、文件上传、API端点和自定义数据存储。虽然Directus本身建立在不同的建筑哲学上,但当其数据处理管道扩展时,工厂方法模式可以应用。例如,自定义扩展可以使用工厂创建不同的“数据适配器”,使从各种第三方服务进入Directus的系统的内容正常化。这保持了核心系统清洁,同时能够快速整合新的数据格式,而无需触及现有的代码。
工厂方法模式的好处
- 打开扩展,关闭修改[] – 可以通过添加新类支持新数据格式,而不是通过编辑现有类。这降低了回归风险。
- Code recuse – 创建类中常见的处理逻辑(如错误处理,记录,缓存)在所有混凝土阅读器中共享.
- 试运行 – 工厂方法在单位测试中可以被推翻,以注入模拟读器,从而可以在不触及真实数据源的情况下孤立地测试业务逻辑.
- Decooppling – 客户端代码仅依赖于抽象([],]]),使其适应具体执行中的变化.
- 单项责任 – 每个混凝土创造者和产品都注重一种格式,遵循单一责任原则.
最佳做法和常见的陷阱
何时使用工厂方法
使用此模式时 :
- 你不知道你系统需要哪类对象
- 您想要为子类提供一个勾钩来扩展对象创建 。
- 您想要重复使用已有对象, 或应用缓存, 而不是每次创建新实例( 工厂方法可以返回集合对象或单顿对象 ) 。
何时避免过度复杂
如果只有一个产品或者选择逻辑是微不足道的(比如总是相同的阅读器 ) , 工厂方法会增加不必要的复杂性。 在这种情况下,简单的构造器或者静态工厂方法(没有子分类)可能就足够了。
与其他图案结合
工厂方法经常与战略(切换算法)和 Template Method[(定义一个算法的骨架,同时将一些步骤推迟到子类)并肩工作. 在数据处理中,创建者可以充当模板方法,在更大的过程中称工厂方法.
结论
工厂方法模式是建立灵活、可维护的工程数据处理系统的一个证明方法。它通过封装对象创建,将“什么”与“如何”脱钩,使团队能够在不破坏现有逻辑的情况下支持新的数据格式和源。 无论您正在建设CAD进口商、IOT管道,还是像Directus那样扩展无头的CMS,这种模式都提供了一种与您要求规模化的清洁架构。 首先,定义一个明确的产品界面,执行每种格式的具体分类,让工厂方法处理即时处理 — — 结果是一个既强健又适应性的系统。
关于工厂方法模式的进一步解读,请检查 重构古鲁解释[和原四书的Gang[. 对于数据工程中的现实世界应用,马丁·福勒的企业应用架构的Patterns也非常推荐.