我实现了这个简短的示例来尝试演示一个简单的委托模式。我的问题是。这看起来我已经理解了委托吗?
class Handler:
def __init__(self, parent = None):
self.parent = parent
def Handle(self, event):
handler = 'Handle_' +event
if hasattr(self, handler):
func = getattr(self, handler)
func()
elif self.parent:
self.parent.Handle(event)
class Geo():
def __init__(self, h):
self.handler = h
def Handle(self, event):
func = getattr(self.handler, 'Handle')
func(event)
class Steve():
def __init__(self, h):
self.handler = h
def Handle(self, event):
func = getattr(self.handler, 'Handle')
func(event)
class Andy():
def Handle(self, event):
print 'Andy is handling %s' %(event)
if __name__ == '__main__':
a = Andy()
s = Steve(a)
g = Geo(s)
g.Handle('lab on fire')
一个 Python 技巧:你不需要说:
func = getattr(self.handler, 'Handle')
func(event)
就说:
self.handler.Handle(event)
我不确定你正在使用 Handler 类做什么,它没有在你的示例中使用。
在 Python 中,具有大写名称的方法非常非常不寻常,通常是移植某些具有此类名称的现有 API 的结果。
这是基本概念,是的 - 将一些传入请求传递给另一个对象来处理。
也想知道同样的事情,Python 似乎不支持委托作为内置功能,并且在这种类型的底层内容上使用大量 opensrc 库进行扩展有时会带来严重的质量风险,因为您添加了依赖项对于或多或少关键领域的第三方来说,这当然完全取决于软件包以及它是否正在积极开发,但仍然如此。
我很久以前就发现通过 C# 了解更多关于委托的知识很有帮助,有很好的文档可以很好地解释它们。
查看评论,我读到 Ashbay 建议您使用 hasattr() 确保类中存在函数。现在,由于您正在使用多个类的委托,而不是函数委托(请参阅 C#,有很好的解释),那么为什么不在您希望通过委托使用的类中使用这两个东西呢:
您可以通过为您的真实类“作为契约”定义一个接口来删除函数调用(节省一次进程运行)。该契约确保契约中的所有内容始终在您的类层次结构链中实现,以履行约定的契约。
接口通常使用内置的 abc python 包(抽象基类)来完成:
看看为什么用作 abc 包(抽象类)来定义接口类有点笨拙:https://interface.readthedocs.io/en/latest/abc.html
通过这个项目,你可以获得这样的常规功能(为什么它们甚至缺失,在强大的 OoP 中非常重要!)。不幸的是,它们还没有内置,但无论如何它在这里:https://pypi.org/project/python-interface/#description
您可以使类更加通用,继承父类,通常使用接口,您可以将它们承包给父类,然后标记抽象并“传递”,以防您希望在子类中实现它们。只有当实现确实发生变化/需要有差异时,您才应该这样做,否则只需使其对所有人通用(如果您继承了很多,则可以节省大量编码时间和代码重复 --> 因此,使用具有抽象方法的抽象基类是这是一个灾难性的模式)。
不确定 python 是否提供了像 C# 中那样进行虚拟重写的好方法,在 C# 中,您可以使用“两者最佳”,这样您就可以仅在真正需要时进行重写,然后默认使用该父类实现。最有可能的是它可以完成,但是 python 有点“叛逆”,因为它做的很多事情都略有不同:)但是,看起来上面链接中的接口 python 包至少对这些有一些支持。
此外,还发现了这个博客,其中讨论了提供多种选项的主题: https://michaelcho.me/article/method-delegation-in-python
选项3中的委托人可能指的是这个库: https://pypi.org/project/ObjectDelegator/
个人观点是,如果您能够并且有时间更准确地设计您的类级别架构,那么在大多数情况下您根本不需要委托。就尝试使代码在循环结构中更加通用和可利用而言,委托应该更像是您的“最后手段”。不管怎样,有时(但很少)你确实需要它们。
ps。我的第一个堆栈溢出评论,如果我在某些外观等样式问题上未能正确,我深表歉意:)