对象生成器模式

时间:2010-10-14 07:50:11

标签: python design-patterns oop factory factory-pattern

我有一个代表一个相当复杂的对象的类。可以通过多种方式创建对象:增量构建,通过解析不同格式的文本字符串以及分析二进制文件。到目前为止,我的策略如下:

  • 让构造函数(在我的情况下为__init__)将所有内部变量初始化为None

  • 提供不同的成员函数来填充对象

  • 让这些函数将新修改过的对象返回给调用者,以便我们可以sd = SuperDuper().fromString(s)

例如:

class SuperDuper:
    def __init__(self):
        self.var1 = None
        self.var2 = None
        self.varN = None

    ## Generators
    def fromStringFormat1(self, s):
        #parse the string
        return self 
    def fromStringFormat2(self, s):
        #parse the string
        return self
    def fromAnotherLogic(self, *params):
        #parse params
        return self
    ## Modifiers (for incremental work)
    def addThis(self, p):
        pass
    def addThat(self, p):
        pass
    def removeTheOtherOne(self, p):
        pass

问题在于课程变得非常庞大。不幸的是,我不熟悉OOP模式设计,但我认为这个问题有一个更优雅的解决方案。是否将生成器函数从类中取出(以便fromString(self, s)成为superDuperFromString(s)一个好主意?

4 个答案:

答案 0 :(得分:3)

在您的情况下,可能更好的主意是依赖注入和控制反转。我们的想法是创建另一个类,其中包含您要解析的所有这些不同来源的所有设置。然后子类可以定义实际解析它的方法。然后,当您实例化该类时,将一个settings类的实例传递给它:

class Settings(object):
    var1 = None
    var2 = None
    var3 = None

    def configure_superduper(self, superduper):
        superduper.var1 = self.var1
        # etc

class FromString(Settings):
    def __init__(self, string):
        #parse strings and set var1, etc.

class SuperDuper(object):
    def __init__(self, settings): # dependency injection  
        settings.configure_superduper(self)  # inversion of control
        # other initialization stuff

sup = SuperDuper(object, FromString(some_string))

这样做的好处是可以更紧密地遵守单一责任原则,该原则规定一个班级应该只有一个(可能会发生)改变的理由。如果您更改了存储任何这些字符串的方式,那么该类必须更改。在这里,我们将每个数据源隔离成一个简单的单独类。

另一方面,如果您认为存储的数据比存储的方式更有可能发生变化,您可能希望使用Ignacio建议的类方法,因为这会(稍微)更复杂并且不会在这种情况下,你真的会买得太多,因为当这种情况发生时你必须改变这个方案中的两个类。当然,它并没有太大的伤害,因为你只需要再改变一项任务。

答案 1 :(得分:2)

我不相信,因为这些都与课程直接相关。

做的是让构造函数接受参数来初始化字段(当然默认为None),然后将所有from*()方法转换为构造的类方法新对象并返回它们。

答案 2 :(得分:1)

我认为在类中包含转换/创建方法并不是一个糟糕的设计。您可以随时将它移动到一个单独的类中,然后您将拥有一个非常轻量级设计模式的简单工厂。

我会让他们留在课堂上:))

答案 3 :(得分:1)

  

让这些函数将新的,修改过的对象返回给调用者,以便我们可以sd = SuperDuper().fromString(s)

这很少是一个好主意。虽然有些Python库类可以做到这一点,但它并不是最好的方法。

一般来说,你想这样做。

class SuperDuper( object ):
    def __init__(self, var1=None, var2=None, var3=None):
        self.var1 = var1
        self.var2 = var2
        self.varN = var3

    def addThis(self, p):
        pass
    def addThat(self, p):
        pass
    def removeTheOtherOne(self, p):
        pass

class ParseString( object ):
    def __init__( self, someString ):
        pass
    def superDuper( self ): 
        pass

class ParseString_Format1( ParseString ):
    pass

class ParseString_Format2( ParseString ):
    pass

def parse_format1( string ):
    parser= ParseString_Format1( string )
    return parser.superDuper()

def parse_format2( string ):
    parser= ParseString_Format2( string )
    return parser.superDuper()

def fromAnotherLogic( **kw ):
    return SuperDuper( **kw )

两个不相关的职责:对象和对象的字符串表示。

不要混淆对象和字符串表示。

对象和解析必须分开。毕竟,编译器不是生成的代码的一部分。 XML解析器和文档对象模型通常是单独的对象。