Skip to main content
 首页 » 编程设计

python之OOP 设计之在 Python 中,这是高质量的 OO 设计还是史诗般的失败

2025年05月04日13xxx_UU

在接受订单的系统中,该订单具有网关交易的付款,对象应该是这样的:

class Order(object): 
        ... Inside init ... 
        self.total_in_dollars = <Dollar Amount> 
        self.is_paid = <Boolean Value> 
 
class Payment(object): 
        ... Inside init ... 
        self.order = order_instance 
        self.amount = order.total_in_dollars 
 
class GatewayTransaction(object): 
        ... Inside init ... 
        self.payment = payment_instance 
        self.amount = <Dollar Amount> 

这似乎是实现它的方法(显然这不是具有整数美元金额等的真实代码,但你明白了)。我这样做是因为订单可以在没有付款的情况下存在,并且付款可以在实际的 PayPal 交易发生之前存在。您认为这是否缺乏?我的想法落后了吗?

或者,应该更像这样:

class GatewayTransaction(object): 
    payment = payment_instance 
    amount = <Dollar Amount> 
 
class Payment(object): 
    amount = <Dollar Amount> 
    gateway_transaction = gateway_transaction_instance 
 
class Order(object): 
    amount_in_dollars = <Dollar Amount> 
    payment = payment_instance 

请您参考如下方法:

您似乎将显然应该是实例 的变量分配为类 变量,这显然是一个非常错误的策略。 IOW,变量应该是 self.total_in_dollars(例如 Order)等等,在 __init__ 中分配,不是 类变量,在 class 语句中赋值!

简单地创建一个 Order 的实例而没有相应的 Payment 是可以的(显然应该将 is_paid 设置为 False),仅基于总数(可能还有一些数字 ID,以便客户 &c 将来可以引用特定订单)。

不要不必要地重复信息!由于 Payment 实例将始终引用 Order 实例,因此它应该不复制 self.order.total_in_dollars 转到 self.amount -- 最好将这些信息放在一个地方(如果你想访问它,你可以创建一个只读的property很好);对于事务实例更是如此。

如果一个 Order 实例携带了进一步的元数据来影响相应的 Payment 实例的创建和行为,那没关系,但强烈建议将 Payment 实例的创建作为 Object 类的工厂方法的工作(然后也可以跟踪已生成的实例,并确保单个给定的订单实例永远不会有超过一个付款实例)。

编辑:既然 OP 对 A 进行了一些编辑,我可以确认第一个版本中的依赖项大致正确的观点(除了,同样,数量不应该被复制这个地方)和那些在第二个版本中的,表面上看,是不正确的(例如,相互/循环依赖的存在总是一种设计味道,除非明确和明确地由特殊的应用程序需求证明是合理的 - 即使需要导航回来等等存在,至少两个链接之一应该是弱引用。

编辑:由于 OP 明确要求提供有关我建议的工厂方法的更多详细信息,因此我的想法是这样的:

import weakref 
 
class Payment(object): 
  def __init__(self, order): 
    self.order = weakref.proxy(order, self.ordergone) 
  def ordergone(self, *_): 
    self.order = None 
  @property 
  def amount(self): 
    if self.order is None: return None 
    else: return self.order.total_in_dollars 
 
class Order(object): 
  def __init__(self, amount): 
    self.total_in_dollars = amount 
    self.is_paid = False 
    self._payment = None 
  @property 
  def payment(self): 
    if self._payment is None: 
      self._payment = Payment(self) 
    return self._payment