抽象工厂模式与委托者模式结合时出现递归错误

问题描述 投票:0回答:2

我正在学习 Python 中的设计模式,并希望将抽象工厂与委托模式结合起来(以更深入地了解该模式的工作原理)。但是,在组合这两种模式时,我遇到了一个奇怪的递归错误,我不明白。

错误是:

  [Previous line repeated 987 more times]
  File "c:\Users\jenny\Documents\design_pattern\creational\abstract_factory.py", line 60, in __getattribute__
    def __getattribute__(self, name: str):

RecursionError: maximum recursion depth exceeded 

当调用

client_with_laptop.display()
时,它会被引发。然而,尽管
client_with_laptop._hardware
返回笔记本电脑实例,但递归错误已在
__init__
期间存储在
factory.get_hardware()
中。

代码是:

from abc import abstractmethod


class ITechnique:
    #abstract product

    @abstractmethod
    def display(self):
        pass

    def turn_on(self):
        print("I am on!")

    def turn_off(self):
        print("I am off!")


class Laptop(ITechnique):
    #concrete product
    def display(self):
        print("I'am a Laptop")

class Smartphone(ITechnique):
    #concrete product
    def display(self):
        print("I'am a Smartphone")

class Tablet(ITechnique):
    #concrete product
    def display(self):
        print("I'm a tablet!")


class IFactory:

    @abstractmethod
    def get_hardware():
        pass

class SmartphoneFactory(IFactory):

    def get_hardware(self):
        return Smartphone()


class LaptopFactory(IFactory):

    def get_hardware(self):
        return Laptop()

class TabletFactory(IFactory):

    def get_hardware(self):
        return Tablet()


class Client():

    def __init__(self, factory: IFactory) -> None:
        self._hardware = factory.get_hardware()

    def __getattribute__(self, name: str):
        return getattr(self._hardware, name)

if __name__ == "__main__":

    client_with_laptop = Client(LaptopFactory())
    client_with_laptop.display()

    client_with_tablet = Client(TabletFactory())
    client_with_tablet.display()

    client_with_smartphone = Client(SmartphoneFactory())
    client_with_smartphone.display()

当我访问属性 _hardware 并删除 get_attribute 部分时(基本上,当我删除委托模式时),一切都会按预期工作。请参阅下面修改后的代码部分,该部分有效:

class Client():

    def __init__(self, factory: IFactory) -> None:
        self._hardware = factory.get_hardware()

if __name__ == "__main__":

    client_with_laptop = Client(LaptopFactory())
    client_with_laptop._hardware.display()

    client_with_tablet = Client(TabletFactory())
    client_with_tablet._hardware.display()

    client_with_smartphone = Client(SmartphoneFactory())
    client_with_smartphone._hardware.display()

任何人都可以帮我解释为什么会出现递归错误或如何修复它。我的目标是(1)根据客户端中使用的工厂拥有不同的设备,并且(2)能够从

_hardware
调用方法,而无需一直键入
client._hardware
而是直接从客户端对象调用它,例如
client.display()
。问题不在于这在现实中是否是一种有用的方法;而在于。我只是想更好地理解该模式以及发生的错误。 :-)

python design-patterns
2个回答
1
投票
from abc import abstractmethod


class ITechnique:
    #abstract product

    @abstractmethod
    def display(self):
        pass

    def turn_on(self):
        print("I am on!")

    def turn_off(self):
        print("I am off!")


class Laptop(ITechnique):
    #concrete product
    def display(self):
        print("I'am a Laptop")

class Smartphone(ITechnique):
    #concrete product
    def display(self):
        print("I'am a Smartphone")

class Tablet(ITechnique):
    #concrete product
    def display(self):
        print("I'm a tablet!")


class IFactory:

    @abstractmethod
    def get_hardware():
        pass

class SmartphoneFactory(IFactory):

    def get_hardware(self):
        return Smartphone()


class LaptopFactory(IFactory):

    def get_hardware(self):
        return Laptop()

class TabletFactory(IFactory):

    def get_hardware(self):
        return Tablet()


class Client():

    def __init__(self, factory: IFactory) -> None:
        self._hardware = factory.get_hardware()

    def __getattribute__(self, name: str):
        return getattr(self._hardware, name)

创建 Client 对象后,该对象具有 方法__getattribute__。在这个方法中你 然后继续调用该对象的 __getattribute__ 方法当您访问此对象的显示方法时。 这会导致即时递归。为了解决这个问题你需要 允许弄清楚需要做什么。 阅读 __getattr____getattribute__ 的文档以确定 你想如何处理它。


0
投票

发生递归错误是因为 Client 类中的 getattribute 方法在尝试访问 _hardware 的属性时触发了递归调用。发生这种情况是因为 getattribute 调用 getattr(self._hardware, name),然后它尝试在 _hardware 属性上再次调用 getattribute,从而导致无限递归。

要解决此问题,您可以通过重写 getattr 方法而不是 getattribute 来显式定义应将哪些属性委托给 _hardware 对象。以下是修改 Client 类的方法:

类客户端: def init(self, 工厂: IFactory) -> 无: self._hardware=factory.get_hardware()

def __getattr__(self, name: str):
    return getattr(self._hardware, name)
© www.soinside.com 2019 - 2024. All rights reserved.