【问题标题】:Calling child class function to reduce code replication调用子类函数减少代码复制
【发布时间】:2019-10-18 18:59:29
【问题描述】:

我希望通过在父类中使用公共代码来减少子类中的代码复制,但仍需要根据子类进行一些更改的特定处理。我知道从父母那里打电话给孩子是不好的。如何完成代码缩减? (或者我应该尝试一下吗?)

这是一个例子:

class Address:

    def __init__(self, street, city, postal_code):

        self._street = street
        self._city = city
        self._postal_code = self.valid_postal_code(postal_code)

    def valid_postal_code(self, postal_code):
        """ Returns a validated postal code """
        #
        # A big bunch of code common to all postal codes
        #

        if child == Usa:
            return Usa.valid_postal_code(postal_code)
        else:
            return Canada.valid_postal_code(postal_code)    

class Usa(Address):

    def valid_postal_code(self, postal_code):
        """ Returns a validated US zip code """
        # Must be 5 digits or 5 digits plus dash 4 digits
        if len(postal_code) != 5 and len(postal_code) != 10:
            raise Exception("Bad postal code")

        return postal_code


class Canada(Address):

    def valid_postal_code(self, postal_code):
        """ Returns a validates Canadian postal code """
        # Must be A#A #A#
        if len(postal_code) == 6:
            postal_code = postal_code[0:3] + " " + postal_code[3:3]
        if len(postal_code) != 7:
            raise Exception("Bad postal code")

        return postal_code.upper()

【问题讨论】:

  • 美国和加拿大的地址实际上没有任何共同之处,只是它们有邮政编码。基本上,Address.valid_postal_code 只会有一个通用的占位符定义(如passreturn Truereturn False),并且每个子类都必须用适当的定义覆盖它。
  • # A big bunch of code common to all postal codes 成为通用部分,但子类中的不同验证逻辑应该保留
  • 每个子节点都应该通过super().valid_postal_code() 调用父节点,而不是父节点调用子节点实现,因为父节点不一定知道(或关心)哪些子节点存在。

标签: python class reduction


【解决方案1】:

每个覆盖方法都应该调用父方法。

class Address:

    def __init__(self, street, city, postal_code):

        self._street = street
        self._city = city
        self._postal_code = self.valid_postal_code(postal_code)

    def valid_postal_code(self, postal_code):
        """ Returns a validated postal code """
        #
        # A big bunch of code common to all postal codes
        #
        ...


class Usa(Address):

    def valid_postal_code(self, postal_code):
        """ Returns a validated US zip code """

        # Must be 5 digits or 5 digits plus dash 4 digits
        if not super().valid_postal_code(postal_code) or len(postal_code) != 5 and len(postal_code) != 10:
            raise Exception("Bad postal code")

        return postal_code


class Canada(Address):

    def valid_postal_code(self, postal_code):
        """ Returns a validates Canadian postal code """
        # Must be A#A #A#
        if len(postal_code) == 6:
            postal_code = postal_code[0:3] + " " + postal_code[3:3]
        if not super().valid_postal_code() or len(postal_code) != 7:
            raise Exception("Bad postal code")

        return postal_code.upper()

【讨论】:

    【解决方案2】:

    有两种可能:

    • 让父代码包含公共部分,子代码包含细节
      • 父级必须返回中间结果

    • 有两个父方法,其中一个是存根并被子方法覆盖
      • 父级将中间结果传递到存根中

    第二种方法看起来像:

    class Address:
    
        def __init__(...):
    
        def valid_postal_code(self, postal_code):
            """ Returns a validated postal code """
            #
            # A big bunch of code common to all postal codes
            #
            return self._validate_postal_code(postal_code)
    
        def _validate_postal_code(self, postal_code):
            raise NotImplementedError
    
    
    class Usa(Address):
    
        def _validate_postal_code(self, postal_code):
            """ Returns a validated US zip code """
            # Must be 5 digits or 5 digits plus dash 4 digits
            if len(postal_code) != 5 and len(postal_code) != 10:
                raise Exception("Bad postal code")
            return postal_code
    
    
    class Canada(Address):
    
        def _validate_postal_code(self, postal_code):
            """ Returns a validates Canadian postal code """
            # Must be A#A #A#
            if len(postal_code) == 6:
                postal_code = postal_code[0:3] + " " + postal_code[3:3]
            if len(postal_code) != 7:
                raise Exception("Bad postal code")
            return postal_code.upper()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-28
      • 1970-01-01
      • 2017-08-25
      • 1970-01-01
      • 1970-01-01
      • 2010-12-14
      相关资源
      最近更新 更多