5

我发现将抽象方法分成两种方法似乎很有用,一种用于公共接口,另一种用于被子类覆盖。

通过这种方式,您可以为输入和输出添加前置条件/​​后置条件检查,使其能够抵御人为错误。

但我在这里关心的是它是否在 python 上可以接受,因为在我的小经验中我从未见过这样的代码。

正常多态性

import abc

class Shape:
    """Abstract base class for shapes"""
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def get_area(self, scale):
        """Calculates the area of the shape, scaled by a factor.
        Do not blame for a silly example.
        """
        pass

class Rectangle(Shape):
    def __init__(self, left, top, width, height):
        self.left = left
        self.top = top
        self.width = width
        self.height = height

    def get_area(self, scale):
        return scale * self.width * self.height

print(Rectangle(10, 10, 40, 40).get_area(3))

# Gosh!... gets tons of 3's
print(Rectangle(10, 10, 40, 40).get_area((3,)))

实现方法分离

import abc

class Shape:
    """Abstract base class for shapes"""
    __metaclass__ = abc.ABCMeta

    def get_area(self, scale):
        """Calculates the area of the shape, scaled by a factor"""

        # preconditions
        assert isinstance(scale, (int,float))
        assert scale > 0

        ret = self._get_area_impl(scale)

        # postconditions
        assert isinstance(ret, (int,float))
        assert ret > 0

        return ret

    @abc.abstractmethod
    def _get_area_impl(self, scale):
        """To be overridden"""
        pass

class Rectangle(Shape):
    def __init__(self, left, top, width, height):
        self.left = left
        self.top = top
        self.width = width
        self.height = height

    def _get_area_impl(self, scale):
        return scale * self.width * self.height

print(Rectangle(10, 10, 40, 40).get_area(3))
print(Rectangle(10, 10, 40, 40).get_area((3,))) # Assertion fails
4

1 回答 1

0

以下是我看到的替代方案,除了你描述的那些:

  1. 使用“实现方法分离”技术,但给它一个更友好的名称(没有下划线,可能是一个将它与公共 API 区分开来的名称,例如get_area_from_validated_scale)。我在我的项目中使用这种技术。
  2. 执行“实现方法分离”技术,用户覆盖该方法但调用进行验证的基类方法。(但是,如果您需要验证输入和输出,则会变得更加复杂。)
  3. 在基类上创建 2 个方法,get_area_validate_inputget_area_validate_output,并要求实现者在每次实现时调用它们get_area
  4. #2 和 #3 的变体,但使用装饰器完成,因此实现者只需将@area_validation其放在方法定义之上。
于 2013-11-16T03:22:09.427 回答