OOP设计 - 在Python中,这是一个高质量的OO设计还是一个史诗般的失败?

oro*_*aki 1 python oop django

在接受具有网关事务的付款的订单的系统中,对象应如下所示:

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>
Run Code Online (Sandbox Code Playgroud)

这似乎是这样做的方式(显然这不是具有整数美元金额的真实代码,但是你得到了图片).我是这样做的,因为订单可以在没有付款情况下存在,并且在实际的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
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 6

你似乎正在分配显然应该是实例变量的变量,这显然是一个非常错误的方法.IOW,变量应该是self.total_in_dollars(例如Order)等等,在语句中分配__init__,而不是类变量class.

简单地创建一个Order没有相应实例的实例Payment很好(并且显然应该设置is_paidFalse),仅基于总数(并且可能是一些数字ID,因此客户和c可以在将来引用特定订单).

不要不必要地复制信息!由于Payment实例将始终有一个参考Order实例,它应该不会复制self.order.total_in_dollarsself.amount-更好地在信息一个地方(你可以做一个只读的property,如果你想很好的访问); 对于事务实例更是如此.

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

编辑:既然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
Run Code Online (Sandbox Code Playgroud)