可扩展程序的良好设计模式

2024-06-06 08:15:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个关于如何为我的程序做一个好的设计的问题。我的程序很简单,但我想有一个好的架构,使我的程序在未来很容易扩展。在

我的程序需要从外部数据源(XML)中获取数据,从这些数据中提取信息,最后需要准备SQL语句将信息导入数据库。因此,对于现在和将来会有的所有外部数据源,我的应用程序有一个简单的“流程”:获取、提取和加载。在

我会从泛型的DataLoader中继承和编写特定的DataLoader类。我想我需要一些工厂设计模式,但是哪种呢?工厂法还是抽象工厂?在

我也不想使用这样的代码:

if data_source == 'X':
     fetcher = XDataFetcher()
elif data_source == 'Y':
     fetcher = YDataFetcher()
....

理想情况下(我不确定这是否容易实现),我想编写新的“数据源处理器”,在现有代码中添加一到两行代码,我的程序将从新的数据源加载数据。在

如何使用设计模式来实现我的目标?如果您能用python提供一些示例,那就太好了。在


Tags: 数据代码程序信息sourcesqldata架构
3条回答

你忽略了最重要的部分,即数据的形状。这才是这里最重要的事情。”“设计模式”是一种分散注意力的东西——许多这种模式的存在是因为Python没有的语言限制,并且引入了不必要的僵化。在

  1. 首先看一下数据的形状。例如。:
    1. 首先是XML
    2. 然后从XML中提取一些数据集合(一个简单的dict?一个嵌套的dict?你需要什么数据?是同质还是异质?这是最重要的事,但你不要说在
    3. 然后在SQL后端序列化/持久化此数据。在
  2. 然后设计方法、属性的“接口”(口头描述),甚至只设计dict或tuple中的项,以方便对数据的操作。如果您保持简单并坚持使用本机Python类型,您甚至可能不需要类,只需要函数和dict/tuples。在
  3. 反复迭代,直到您拥有应用程序所需的抽象级别。在

例如,“提取器”的接口可能是“生成xml字符串的iterable”。注意这可以是生成器一个具有__iter__next()方法的类!不需要定义抽象类和子类!在

添加到数据中的可配置多态性类型取决于数据的确切形状。例如,您可以使用约定:

# persisters.py

def persist_foo(data):
    pass

# main.py
import persisters

data = {'type':'foo', 'values':{'field1':'a','field2':[1,2]}}
try:
   foo_persister = getitem(persisters, 'persist_'+data['type'])
except AttributeError:
   # no 'foo' persister is available!

或者,如果需要进一步抽象(可能需要添加无法控制的新模块),可以使用注册表(只是dict)和模块约定:

^{pr2}$

如果需要,您可以轻松地在这个结构之上构建一个全局注册表(尽管您应该避免使用全局状态,即使这样做不太方便)

如果您正在构建公共框架,并且您需要最大限度的可扩展性和形式主义,并且愿意为复杂性付出代价,那么您可以看看^{}。(金字塔使用)

您是否考虑过scrapy而不是使用自己的提取转换加载应用程序?使用scrapy,您可以编写一个“Spider”,它给定一个字符串并返回项目(您的数据)或请求的序列(请求更多的字符串,例如要获取的url)。这些项被发送到一个可配置的项管道中,在传递它们之前,它对接收到的项做任何它想做的事情(例如,在数据库中持久化)。在

即使您不使用Scrapy,您也应该采用类似于数据中心的管道设计,并且更喜欢用抽象的“可调用”和“iterable”接口来思考,而不是具体的“类”和“模式”。在

您要做的是动态导入模块(它基于一些基类)。很像动态dll加载的c++用例。在

尝试以下操作SO question。以及^{}的python文档(它只是__import__的包装)

import importlib
moduleToImport = importlib.import_module("moduleName")

如果所有取数器都具有相同的接口,则可以使用字典:

fetcher_dict = {'X':XDataFetcher,'Y':YDataFetcher}
data_source = ...
fetcher = fetcher_dict[data_source]()

至于保持灵活性——只需编写干净的惯用代码。我倾向于喜欢“你不需要它”的哲学。如果您花费太多时间试图展望未来以确定您将需要什么,那么当您发现实际需要什么时,您的代码将过于臃肿和复杂,无法进行简单的调整。如果代码是预先清理的,那么以后重构以满足您的需要应该很容易。在

相关问题 更多 >