【问题标题】:Can Interface Segregation Principle be applied to Python objects?接口隔离原则可以应用于 Python 对象吗?
【发布时间】:2021-03-08 06:12:09
【问题描述】:

为了将SOLID 原则应用到一个有机增长且需要重构的 Python 项目,我试图了解如何将 Interface Segregation Principle 应用于Python 语言,当接口不作为语言功能存在时?

【问题讨论】:

  • 我没有提到这是关于 2.7 项目的问题,但我对 3.x 和 2.7 的答案很感兴趣。

标签: python solid-principles interface-segregation-principle


【解决方案1】:

接口是您可以在源代码中直接输入提示或在文档中非正式地输入提示的东西。 Python 3 支持 function annotations,实际支持 3.5+ type hints,即使所有这些都不存在,您仍然可以在文档中简单地输入提示。类型提示只是表示特定参数应具有特定特征。

具体来说:

interface Foo {
    string public function bar();
}

function baz(Foo obj) { .. }

所有这一切都是声明传递给baz的任何参数都应该是一个带有bar方法的对象,该方法不接受任何参数并返回一个字符串。即使 Python 没有在语言级别实现任何强制,您仍然可以通过多种方式声明这些东西。

Python 确实支持两个重要的东西:abstract classes 和多重继承。

在 Python 中,您可以这样做,而不是 interface Foo

import abc

class Foo(abc.ABC):
    @abc.abstractmethod
    def bar() -> str:
        pass

你可以使用implements Foo,而不是:

class MyClass(Foo):
    def bar() -> str:
        return 'string'

您可以使用 function baz(Foo obj) 代替:

def baz(obj: Foo):
    obj.bar()

由于多重继承特性,您可以根据需要尽可能精细地隔离接口/抽象类。

Python 是基于鸭子类型的原则,所以不是通过接口声明和继承来强制执行所有这些,它通常更宽松地定义为“参数必须是可迭代的”等,调用者只需要确保参数是可迭代的。抽象类和函数注释,再加上正确的开发工具,可以帮助开发人员在不同的执行级别上遵守此类合同。

【讨论】:

  • 感谢您的全面回答。我忘了提到这是一个 2.7 项目,但你也涵盖了。我期待在未来探索 Python 3 更高级的特性。
  • 由于 Python 著名的 duck typing 特性,接口不像其他编程语言那样广泛使用。如果一个物体像鸭子一样走路,像鸭子一样游泳,那么 Python 很乐意将其视为鸭子,即使它是天鹅!
【解决方案2】:

保持接口小并达到减少耦合的目的。耦合是指两个软件之间连接的紧密程度。接口定义的越多,实现类也需要做的越多。这使得该类可重用性降低

我们来看一个简单的例子:


from abc import abstractmethod


class Machine:
    def print(self, document):
        raise NotImplementedError()

    def fax(self, document):
        raise NotImplementedError()

    def scan(self, document):
        raise NotImplementedError()


# ok if you need a multifunction device
class MultiFunctionPrinter(Machine):
    def print(self, document):
        pass

    def fax(self, document):
        pass

    def scan(self, document):
        pass


class OldFashionedPrinter(Machine):
    def print(self, document):
        # ok - print stuff
        pass

    def fax(self, document):
        pass  # do-nothing

    def scan(self, document):
        """Not supported!"""
        raise NotImplementedError('Printer cannot scan!')


class Printer:
    @abstractmethod
    def print(self, document): pass


class Scanner:
    @abstractmethod
    def scan(self, document): pass


# same for Fax, etc.

class MyPrinter(Printer):
    def print(self, document):
        print(document)


class Photocopier(Printer, Scanner):
    def print(self, document):
        print(document)

    def scan(self, document):
        pass  # something meaningful


class MultiFunctionDevice(Printer, Scanner):  # , Fax, etc
    @abstractmethod
    def print(self, document):
        pass

    @abstractmethod
    def scan(self, document):
        pass


class MultiFunctionMachine(MultiFunctionDevice):
    def __init__(self, printer, scanner):
        self.printer = printer
        self.scanner = scanner

    def print(self, document):
        self.printer.print(document)

    def scan(self, document):
        self.scanner.scan(document)


printer = OldFashionedPrinter()
printer.fax(123)  # nothing happens
printer.scan(123)  # oops!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-09
    • 2016-10-19
    • 2021-11-12
    • 2021-01-12
    • 1970-01-01
    相关资源
    最近更新 更多