Python 类工厂...还是其他?

2 投票
3 回答
2601 浏览
提问于 2025-04-11 09:27

我们有一个用C#写的数据库库,可以这样使用:

DatabaseConnection conn = DatabaseConnection.FromConnectionString("...");

这个库隐藏了不同数据库引擎之间的许多差异,比如SQL函数名称、参数名称和规格等等。

在内部,DatabaseConnection类是一个抽象类,它实现了一些基本的方法。但是,FromConnectionString方法会遍历一系列注册的特殊类型,这些类型处理实际的差异,并构造出正确的类对象。换句话说,我得到的不是一个DatabaseConnection对象,而是一个MSSQLDatabaseConnection或OracleDatabaseConnection对象,这些对象当然是从DatabaseConnection继承而来的。

连接字符串包含了关于这个连接所使用的数据库引擎和版本的信息。

我想在Python中创建一个类似的库。正确的方法是像这样构造吗?

conn = DatabaseConnection("...")

或者使用类方法呢?

conn = DatabaseConnection.FromConnectionString("...")

第一个方法是否可行,也就是说... 能否像这样构造一个对象,并根据传入字符串中的数据返回其他的、特定的对象?

好吧,让我换个问题... 在Python中,做这件事的pythonic方式是什么?

我基本上想在Python中也有一个DatabaseConnection基类,实现一些共同的方法,并在派生类中进行特化,同时有一个方法或函数,根据连接字符串构造并返回正确类型的对象。

3 个回答

1

第一个方法绝对是可行的,而且在我看来更好。在Python中,构造函数其实没有什么特别复杂的地方。简单来说,它们就像其他函数一样。我用过这种设计模式几次,来表示一个类不应该被直接实例化,比如:

def DatabaseConnectionFromString(connection_string)
    return _DatabaseConnection(connection_string)

def DatabaseConnectionFromSomethingElse(something_else)
    connection_string = convert_something_else_into_string(something_else)
    return _DatabaseConnection(connection_string)

class _DatabaseConnection(object):
    def __init__(self, connection_string):
        self.connection_string = connection_string

当然,这只是一个简单的例子,但应该能给你一个大致的概念。

补充:在Python中,继承并没有那么被看作坏事。这种方式你也可以使用:

DatabaseConnection(object):
    def __init__(self, connection_string):
        self.connection_string = connection_string

DatabaseConnectionFromSomethingElse(object)
    def __init__(self, something_else):
        self.connection_string = convert_something_else_into_string(something_else)

抱歉说得有点多,但我想让它更清楚。

3

Python并不在乎你返回的是什么类型。

def DatabaseConnection( str ):   
    if ( IsOracle( str ) ):   
        return OracleConnection( str )  
    else: 
        return SomeOtherConnection( str )
5

在Python中,这是可以做到的,但可能不是最好的方法。类工厂模式其实是为了那些没有“第一类类”的语言而想出的一个解决办法。因为Python本身就有“第一类类”,你可以把一个类存储在一个变量里,然后直接用这个类来创建实例。如果你想改变创建的类,只需要把另一个类存储到那个变量里就行了。

举个例子:

class class1:
  def greet(self):
    print "hi"

class class2:
  def greet(self):
    print "hello"

maker = class1
obj1 = maker()

maker = class2
obj2 = maker()

obj1.greet() # prints "hi"
obj2.greet() # prints "hello"

撰写回答