类与参数化实例

时间:2012-10-12 22:34:10

标签: python oop class design-patterns architecture

假设我有一个类层次结构。理论上,我可以通过为实例提供额外的参数来维护其功能。这是一个例子(超级设计,但我想保持简单):

class Base:
  def __init__(self, a):
    self.a = a
  def f(self, x):
    raise NotImplemented # needs to be defined in subclass

class Mult(Base)
  def f(self, x):
    return self.a * x

class Add(Base):
  def f(self, x):
    return self.a + x

m = Mult(5)
a = Add(7)
m.f(10)
a.f(20)

以上代码可以重构为:

class Compute:
  def __init__(self, a, func):
    self.a = a
    self.func = func
  def f(self, x)
    return self.func(self.a, x)

m = Compute(5, operator.mult)
a = Compute(7, operator.add)

我明白,对于这个愚蠢的例子,它没有任何区别。因此,除了理解我的观点外,请不要考虑它。

我想知道在为现实生活中遇到的各种情况做出选择时,我应该考虑哪些因素?换句话说,使用类与参数化实例的优缺点是什么?

3 个答案:

答案 0 :(得分:1)

在第一个示例中,您使用固定方式为客户端代码提供了一组固定的操作。它很容易繁殖,但是如果你想要分而为之,那就是运气不好。

在第二个示例中,您将实现详细信息推送到客户端。您现在拥有一个完整的操作无关的计算框架。这需要更多的客户端代码知识。

因此,真正不同的是抽象级别 - 您希望客户具备哪些知识。如果对于operator.mult使用{{1}}的客户端非常重要,而不是其他逻辑(例如,XML-RPC到乘法服务器),则第二个选项似乎是合适的。如果客户端比你更了解如何处理这两个数字,并且你想只提供一个框架(一个包装的类型),第二个选项更好。如果你只是想让人们添加和增加东西,第一个选择就更好了。

答案 1 :(得分:1)

这实际上取决于课程的作用。在你的例子中,类中的逻辑很小,很明显你只是为类提供了包装方法。拥有计算类更有意义。

在现实生活中,你应该问问自己cohesive是如何组合在一起的不同功能。虽然单一责任很重要,但你不需要接受那个荒谬的广告

答案 2 :(得分:0)

我想这取决于你是否会获得有关转换的所有信息(?),你将对施工时可用的物体做些什么。如果不这样做,则无法调用更复杂的构造函数。

此外,将选项打开以对“基本”对象执行操作之前,在将其提交到某个路径之前通常是有帮助的,即使在最初设计类时不明显。

一般情况下,我发现使用最小必需参数创建构造函数并通过方法实现任何其他功能是最佳解决方案。

本着随机例子的精神,考虑:

参数化构造函数

class Image:
    # Some implementation

class Text:
    def __init__(self, image, whitelistChars):
        # This uses OCR to extract the text from an image then filters out 
        #   non-whitelisted characters
        #
        # image is an Image
        # whitelistChars is an interable containing characters that should 
        #   not be filtered out

im = Image('scan.tif')
t = Text(im, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ134567890');

基本构造函数

class Text:
    def __init__(self, image):
        # This uses OCR to extract the text from an image
        #
        # image is an Image


    def filter(self, whitelistChars):
        # This filters out non-whitelisted characters
        #
        # whitelistChars is an interable containing characters that should 
        #   not be filtered out

im = Image('scan.tif')
t = Text(im)
# <-- Are you interested in doing anything to the Text object t here?
t.filter('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ134567890')

在“基本构造函数”实现中,您可以选择在剥离非白名单字符之前使用Text对象t。也许这有用吗?也许更重要的是,也许这将来会有用吗?

如果你可以自信地说“不”,它就没用了,从来没有我认为“参数化构造函数”没问题。如果有的话,它就不需要额外的filter电话。

但是,如果你希望重用代码,那么在转换它之前(或者只是过滤文本),打开操作t的选项,或者甚至只是检查它,通常是有用的。

(我的$ 0.02)