【问题标题】:Class design: methods that share a lot of the same code类设计:共享大量相同代码的方法
【发布时间】:2012-09-21 12:38:24
【问题描述】:

此时我想创建一个有两个方法的类(我也希望能够 明显改变班级)。

class ogrGeo(object):

    def __init__(self):
        pass

    def CreateLine(self, o_file, xy):
        #lots of code


    def CreatePoint(self, o_file, xy):
        # lot's of the same code as CreateLine(), 
        # only minor differences

保持事物干净并重复 尽可能少的代码我正在寻求一些建议。两种方法CreateLine()CreatePoint() 分享了很多代码。减少冗余: 是否应该定义两种方法都可以调用的第三种方法? 在这种情况下,您仍然可以致电 o = ogrGeo() o.CreateLine(...) o.CreatePoint(...)seperatly。 还是应该将它们合并为一种方法?还有其他我没有想到或一无所知的解决方案吗?

已经感谢您的任何建议。

【问题讨论】:

  • 感谢大家的建议。最后,我将它实现为一个具有两个公共方法和两个辅助函数的类,以尽可能多地模块化代码。我对结果很满意,特别是因为它的代码将使我的类的扩展非常容易(例如方法create_polygon,...)。

标签: python oop methods


【解决方案1】:

是否应该将这些方法合并为一个是 API 设计的问题。如果这些功能有不同的目的,那么你将它们分开。如果客户端代码可能遵循该模式,我合并它们

if some_condition:
    o.CreateLine(f, xy)
else:
    o.CreatePoint(f, xy)

但除此之外,不要合并。相反,如果公共代码不涉及self,则将公共代码重构为私有方法,甚至是独立函数。 Python 没有内置于语言中的“私有方法”的概念,但带有前导 _ 的名称将被识别为此类。

【讨论】:

  • 如果我决定使用独立函数,继承如何?你不应该总是把你的类派生的代码放在一起吗?
  • @larsvegas:为什么?这意味着你永远不能在课堂之外调用任何东西。我倾向于将实用程序函数放在模块中而不是类中,但如果你不喜欢这样,你可以使用staticmethod。 Python 不是 Java :)
  • 不,我不是这个意思。但是如果你基于ogrGeo 派生一个类,如果它是独立的,你就不会继承实用函数,对吧?
  • @larsvegas:啊,没错。这使得它成为类设计的问题:您希望该方法是私有的还是“受保护的”,就像 Java 和 C++ 所说的那样?请注意,当派生类覆盖实用程序方法而不是 CreateLine 时,它仍然会更改 ClassLine 的行为。
【解决方案2】:

将通用代码分解为(私有)辅助方法是完全正常的:

class ogrGeo(object)
    def __init__(self):
        pass

    def CreateLine(self, o_file, xy):
        #lots of code
        value = self._utility_method(xy)

    def CreatePoint(self, o_file, xy):
        # lot's of the same code as CreateLine(), 
        # only minor differences
        value = self._utility_method(xy)

    def _utility_method(self, xy):
        # Common code here
        return value

该方法可以返回一个值,也可以直接操作self 上的属性。

忠告:阅读Python style guide 并遵守其约定。大多数其他 python 项目都这样做,如果你这样做,它将使其他 Python 开发人员更容易理解你的代码。

【讨论】:

  • 你指的是我的方法名称,我想......是的。我的坏习惯。
【解决方案3】:

对于将重叠的代码段,请考虑它们是否也可以是它们自己的独立函数。那么CreateLine 将由对某些函数的多个调用组成,参数选择对CreateLine 有意义,同时CreatePoint 将是几个函数调用,具有用于创建点的适当参数。

即使这些新的辅助功能不会在其他地方使用,最好将它们模块化为单独的功能,而不是复制/粘贴代码。但是,如果创建这些结构所需的辅助函数非常具体,那么为什么不将它们分解为自己的类呢?

您可以创建一个“对象”类,其中包含创建对象的所有基础知识,然后具有派生自“对象”的“线”和“点”类。在这些类中,覆盖必要的函数,以便构造是特定的,依赖于基“Object”类中的辅助函数来处理重叠的部分代码。

然后ogrGeo 类将构造这些其他类的实例。即使“线”或“形状”的最终消费者不需要完整的类对象,您仍然可以使用这种设计,并让ogrGeo 能够返回 Line 实例或 Point 的子片段消费者确实希望使用的实例。

【讨论】:

    【解决方案4】:

    这无关紧要。您希望类方法对调用程序尽可能可用,并且使用两个方法比使用单个方法和要创建的对象类型的附加参数更容易和更有效:

    def CreateObj(self, obj, o_file, xy)    # obj = 0 for Point, 1 for Line, ...
    

    建议:使用单独的 API 调用并将通用代码分解为可在您的类中调用的方法。

    【讨论】:

      【解决方案5】:

      你也可以去另一个方向。尤其是在以下情况下:

      def methA/B(...):
          lots of common code
          small difference
          lots of common code
      

      那你就可以了

      def _common(..., callback):
          lots of common code
          callback()
          lots of common code
      def methA(...):
          def _mypart(): do what A does
          _common(..., _mypart)
      def methB(...):
          def _mypart(): do what B does
          _common(..., _mypart)
      

      【讨论】:

        猜你喜欢
        • 2020-10-02
        • 1970-01-01
        • 2014-12-01
        • 2023-02-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-27
        • 1970-01-01
        • 2011-10-17
        相关资源
        最近更新 更多