我有一个代表一个相当复杂的对象的类。可以通过多种方式创建对象:增量构建,通过解析不同格式的文本字符串以及分析二进制文件。到目前为止,我的策略如下:
让构造函数(在我的情况下为__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)
一个好主意?
答案 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解析器和文档对象模型通常是单独的对象。