根据类的输入,需要在公共接口(此处称为method
)下使用不同的方法。哪一个更像Pythonic?
尝试#1
class ExampleClass(object):
def __init__(self, a=None, b=None):
self.a = a
self.b = b
if a is not None:
self.method = self._a_method
else:
self.method = self._b_method
def method(self):
raise NotImplementedError
def _method_a(self):
return "I am a method that relies on input: " + self.a
def _method_b(self):
return "I am a method that relies on input: " + self.b
或尝试#2:
class ExampleClass(object):
def __init__(self, a=None, b=None):
self.a = a
self.b = b
def method(self):
if self.a is not None:
return self._method_a(self)
else:
return self._method_b(self)
def _method_a(self):
return "I am a method that relies on input: " + self.a
def _method_b(self):
return "I am a method that relies on input: " + self.b
在这种情况下可能并不重要,但在我的情况下,我有多个method
,意味着方法#2违反了DRY原则(每个都有相同的if,else逻辑)各种method
s)。
另一方面,在_method_*
中动态分配__init__
函数是否尴尬,因为它在尝试#1中失败了?
答案 0 :(得分:0)
我想说这两种方法都显示出糟糕的OOP设计,我相信应该避免,除非您的整个ExampleClass
API(包括构造函数)已经向客户公开,并且应该保留以便向后兼容。如果不是这种情况,我认为应该使用Factory pattern的某些变体,可能类似http://www.drdobbs.com/jvm/creating-and-destroying-java-objects-par/208403883中描述的“静态工厂方法”。使用这种方法,您可以根据参数轻松创建不同子类型的对象。此外,您可以提供不同名称的不同工厂方法,以更好地反映已创建对象的含义,而不仅仅是分析参数。
如果您的API应该被保留并且性能不是非常重要(并且考虑到您使用Python,我认为它是理所当然的),我会投票给ExampleClass
一个包装器,它将所有实际工作委托给通过工厂创建的内部委托。像这样:
class ExampleClass(object):
def __init__(self, a=None, b=None):
if a is not None:
self._delegate = ExampleAImpl(a)
else:
self._delegate = ExampleBImpl(b)
def method(self):
return self._delegate.methodImpl()
class ExampleAImpl(object):
def __init__(self, a):
self.a = a
def methodImpl(self):
return "I am a method that relies on input: " + self.a
class ExampleBImpl(object):
def __init__(self, b):
self.b = b
def methodImpl(self):
return "I am a method that relies on input: " + self.b
注意:此方法不适用于ExampleClass
的继承。此外,如果您仍需要将a
和b
作为公共属性,则可以完成此操作,但会使代码更加复杂。