【问题标题】:Python design pattern: class that returns different objects depending on parametersPython设计模式:根据参数返回不同对象的类
【发布时间】:2023-04-04 17:44:01
【问题描述】:

这个问题涉及 Python 中的设计模式,是针对软件设计人员的。

我有几个类继承自同一个抽象类(它们都有类似的接口,但成员函数有非常不同的实现)。我想创建一个结合(包装)所有这些的类(或其他东西)。通过组合,我的意思是根据输入参数创建并返回某个类的对象的模式。最简单的解决方案是 Python 函数:

def fabric_function(arg):
    if isinstance(arg, float):
        return Class1(arg)
    if isinstance(arg, str):
        return Class2(arg)

有没有更好的模式可以做到这一点?我真的希望它是一个根据参数返回Class1Class2 对象的类。我希望用户根据输入参数创建一个类Class 的实例,该类作为Class1Class2 的实例运行,因此用户不必决定使用哪一个以及type(obj) 的输出在所有情况下都应该是 Class。在这种情况下,我可以修改负责对象制作过程的成员函数__new__,但我不确定这是一种干净的方法。也许我应该使用多重继承并在构造函数中决定真正继承哪个父类?

【问题讨论】:

  • type(obj) 的输出在所有情况下都应该是 Class。这个要求有多难?目的是什么?拥有 Class1 Class2 工厂很容易。 可能(使用type 即时创建一个类)在这两种情况下都有一个说 Class 的方法,但坦率地说,这是一种可怕的 hack,对消费者来说既不清楚,也不一定对 isinstance 之类的东西有好处.如果这是一个硬要求,闻起来像 XY 问题。
  • 这并不难,但我不想让用户知道 Class1 和 Class2 的存在,它们是技术类,与他/她要去的库接口无关使用。
  • 就像我说的,这是一个hack。您正在为实际的最终用户永远不会关心并且程序员用户会讨厌的东西引入奇怪的行为。 XY 问题。在任何情况下,pythonic 类检查行为都围绕isinstance,而不是type。这对于 linter 抱怨 type 而不是 isinstance 使用的语言来说已经足够核心了。因此,同样,知情的用户不会在他们的代码中使用type,尽管他们可能会在 repl 中使用。
  • 这听起来像是严重的 OO 滥用,您没有为 “我不希望用户知道 Class1 和 Class2 的存在”提供任何理由。是权限还是隐蔽性安全,例如一个是Employee.request_pay_rise,另一个是Manager.approve_pay_rise?请显示有关 Class1、Class2 的更多细节以及为什么它们设法成为同级类,但您想掩盖它们的关系。如果“它们是技术类,与他/她将要使用的库接口无关”,那么只需给公共父类起一个晦涩的名称,以“_”开头

标签: python oop design-patterns abstract-class multiple-inheritance


【解决方案1】:

我认为Class1Class2 以某种方式相关(例如,“Square”和“Circle”都是“Figures”)。你所描述的是一个抽象工厂。

您需要一个公开Create() 方法的类,接受可以帮助您找出要实例化的具体实现的最低限度的上下文。

【讨论】:

    【解决方案2】:

    我曾经使用字典做过类似的事情。我要求派生类的 init 函数具有相同的签名才能工作。

    使用您选择的某些不可变类型的字典作为键并将类名作为值:

    TYPE_MAP = {typeA: Class1,
                typeB: Class2,
                typeC: Class3}
    
    def fabric_function(arg):
        return TYPE_MAP[type(arg)](arg)
    

    我不完全确定您对 pythonic/clean 的看法,但它极大地帮助我避免了您在上面发布的 if isinstance... 链。而且它很容易扩展,你只需要调整字典而不是工厂函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 2018-08-17
      • 2021-08-29
      • 1970-01-01
      相关资源
      最近更新 更多